LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/xplane - ogr_xplane_apt_reader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1405 1290 91.8 %
Date: 2010-01-09 Functions: 70 67 95.7 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogr_xplane_apt_reader.cpp
       3                 :  *
       4                 :  * Project:  X-Plane apt.dat file reader
       5                 :  * Purpose:  Implements OGRXPlaneAptReader class
       6                 :  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2008, Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  *
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  *
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      22                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "ogr_xplane_apt_reader.h"
      31                 : #include "ogr_xplane_geo_utils.h"
      32                 : 
      33                 : CPL_CVSID("$Id: ogr_xplane_apt_reader.cpp 18425 2010-01-02 20:00:18Z rouault $");
      34                 : 
      35                 : /************************************************************************/
      36                 : /*                   OGRXPlaneCreateAptFileReader                       */
      37                 : /************************************************************************/
      38                 : 
      39               1 : OGRXPlaneReader* OGRXPlaneCreateAptFileReader( OGRXPlaneDataSource* poDataSource )
      40                 : {
      41               1 :     OGRXPlaneReader* poReader = new OGRXPlaneAptReader(poDataSource);
      42               1 :     return poReader;
      43                 : }
      44                 : 
      45                 : /************************************************************************/
      46                 : /*                         OGRXPlaneAptReader()                         */
      47                 : /************************************************************************/
      48               0 : OGRXPlaneAptReader::OGRXPlaneAptReader()
      49                 : {
      50               0 : }
      51                 : 
      52                 : /************************************************************************/
      53                 : /*                         OGRXPlaneAptReader()                         */
      54                 : /************************************************************************/
      55                 : 
      56               1 : OGRXPlaneAptReader::OGRXPlaneAptReader( OGRXPlaneDataSource* poDataSource )
      57                 : {
      58               1 :     poInterestLayer = NULL;
      59                 : 
      60               1 :     poAPTLayer = new OGRXPlaneAPTLayer();
      61               2 :     poRunwayLayer = new OGRXPlaneRunwayLayer();
      62               2 :     poRunwayThresholdLayer = new OGRXPlaneRunwayThresholdLayer();
      63               2 :     poStopwayLayer = new OGRXPlaneStopwayLayer();
      64               2 :     poWaterRunwayLayer = new OGRXPlaneWaterRunwayLayer();
      65               2 :     poWaterRunwayThresholdLayer = new OGRXPlaneWaterRunwayThresholdLayer();
      66               2 :     poHelipadLayer = new OGRXPlaneHelipadLayer();
      67               2 :     poHelipadPolygonLayer = new OGRXPlaneHelipadPolygonLayer();
      68               2 :     poTaxiwayRectangleLayer = new OGRXPlaneTaxiwayRectangleLayer();
      69               2 :     poPavementLayer = new OGRXPlanePavementLayer();
      70               2 :     poAPTBoundaryLayer = new OGRXPlaneAPTBoundaryLayer();
      71               2 :     poAPTLinearFeatureLayer = new OGRXPlaneAPTLinearFeatureLayer();
      72               2 :     poATCFreqLayer = new OGRXPlaneATCFreqLayer();
      73               2 :     poStartupLocationLayer = new OGRXPlaneStartupLocationLayer();
      74               2 :     poAPTLightBeaconLayer = new OGRXPlaneAPTLightBeaconLayer();
      75               2 :     poAPTWindsockLayer = new OGRXPlaneAPTWindsockLayer();
      76               2 :     poTaxiwaySignLayer = new OGRXPlaneTaxiwaySignLayer();
      77               2 :     poVASI_PAPI_WIGWAG_Layer = new OGRXPlane_VASI_PAPI_WIGWAG_Layer();
      78                 : 
      79               1 :     poDataSource->RegisterLayer(poAPTLayer);
      80               1 :     poDataSource->RegisterLayer(poRunwayLayer);
      81               1 :     poDataSource->RegisterLayer(poRunwayThresholdLayer);
      82               1 :     poDataSource->RegisterLayer(poStopwayLayer);
      83               1 :     poDataSource->RegisterLayer(poWaterRunwayLayer);
      84               1 :     poDataSource->RegisterLayer(poWaterRunwayThresholdLayer);
      85               1 :     poDataSource->RegisterLayer(poHelipadLayer);
      86               1 :     poDataSource->RegisterLayer(poHelipadPolygonLayer);
      87               1 :     poDataSource->RegisterLayer(poTaxiwayRectangleLayer);
      88               1 :     poDataSource->RegisterLayer(poPavementLayer);
      89               1 :     poDataSource->RegisterLayer(poAPTBoundaryLayer);
      90               1 :     poDataSource->RegisterLayer(poAPTLinearFeatureLayer);
      91               1 :     poDataSource->RegisterLayer(poATCFreqLayer);
      92               1 :     poDataSource->RegisterLayer(poStartupLocationLayer);
      93               1 :     poDataSource->RegisterLayer(poAPTLightBeaconLayer);
      94               1 :     poDataSource->RegisterLayer(poAPTWindsockLayer);
      95               1 :     poDataSource->RegisterLayer(poTaxiwaySignLayer);
      96               1 :     poDataSource->RegisterLayer(poVASI_PAPI_WIGWAG_Layer);
      97               1 : }
      98                 : 
      99                 : /************************************************************************/
     100                 : /*                        CloneForLayer()                               */
     101                 : /************************************************************************/
     102                 : 
     103               0 : OGRXPlaneReader* OGRXPlaneAptReader::CloneForLayer(OGRXPlaneLayer* poLayer)
     104                 : {
     105               0 :     OGRXPlaneAptReader* poReader = new OGRXPlaneAptReader();
     106                 : 
     107               0 :     poReader->poInterestLayer = poLayer;
     108               0 :     SET_IF_INTEREST_LAYER(poAPTLayer);
     109               0 :     SET_IF_INTEREST_LAYER(poRunwayLayer);
     110               0 :     SET_IF_INTEREST_LAYER(poRunwayThresholdLayer);
     111               0 :     SET_IF_INTEREST_LAYER(poStopwayLayer);
     112               0 :     SET_IF_INTEREST_LAYER(poWaterRunwayLayer);
     113               0 :     SET_IF_INTEREST_LAYER(poWaterRunwayThresholdLayer);
     114               0 :     SET_IF_INTEREST_LAYER(poHelipadLayer);
     115               0 :     SET_IF_INTEREST_LAYER(poHelipadPolygonLayer);
     116               0 :     SET_IF_INTEREST_LAYER(poTaxiwayRectangleLayer);
     117               0 :     SET_IF_INTEREST_LAYER(poPavementLayer);
     118               0 :     SET_IF_INTEREST_LAYER(poAPTBoundaryLayer);
     119               0 :     SET_IF_INTEREST_LAYER(poAPTLinearFeatureLayer);
     120               0 :     SET_IF_INTEREST_LAYER(poATCFreqLayer);
     121               0 :     SET_IF_INTEREST_LAYER(poStartupLocationLayer);
     122               0 :     SET_IF_INTEREST_LAYER(poAPTLightBeaconLayer);
     123               0 :     SET_IF_INTEREST_LAYER(poAPTWindsockLayer);
     124               0 :     SET_IF_INTEREST_LAYER(poTaxiwaySignLayer);
     125               0 :     SET_IF_INTEREST_LAYER(poVASI_PAPI_WIGWAG_Layer);
     126                 : 
     127               0 :     if (pszFilename)
     128                 :     {
     129               0 :         poReader->pszFilename = CPLStrdup(pszFilename);
     130               0 :         poReader->fp = VSIFOpen( pszFilename, "rt" );
     131                 :     }
     132                 : 
     133               0 :     return poReader;
     134                 : }
     135                 : 
     136                 : /************************************************************************/
     137                 : /*                               Rewind()                               */
     138                 : /************************************************************************/
     139                 : 
     140               1 : void OGRXPlaneAptReader::Rewind()
     141                 : {
     142               1 :     bAptHeaderFound = FALSE;
     143               1 :     bTowerFound = FALSE;
     144               1 :     dfLatTower = 0;
     145               1 :     dfLonTower = 0;
     146               1 :     dfHeightTower = 0;
     147               1 :     bRunwayFound = FALSE;
     148               1 :     dfLatFirstRwy = 0;
     149               1 :     dfLonFirstRwy = 0;
     150                 : 
     151               1 :     bResumeLine = FALSE;
     152                 : 
     153               1 :     OGRXPlaneReader::Rewind();
     154               1 : }
     155                 : 
     156                 : 
     157                 : /************************************************************************/
     158                 : /*                      IsRecognizedVersion()                           */
     159                 : /************************************************************************/
     160                 : 
     161               1 : int OGRXPlaneAptReader::IsRecognizedVersion( const char* pszVersionString)
     162                 : {
     163                 :     return EQUALN(pszVersionString, "850 Version", 11) ||
     164               1 :            EQUALN(pszVersionString, "810 Version", 11);
     165                 : }
     166                 : 
     167                 : /************************************************************************/
     168                 : /*                                Read()                                */
     169                 : /************************************************************************/
     170                 : 
     171               1 : void OGRXPlaneAptReader::Read()
     172                 : {
     173                 :     const char* pszLine;
     174                 : 
     175               1 :     if (!bResumeLine)
     176                 :     {
     177                 :         CPLAssert(papszTokens == NULL);
     178                 :     }
     179                 : 
     180             705 :     while(bResumeLine || (pszLine = CPLReadLine(fp)) != NULL)
     181                 :     {
     182                 :         int nType;
     183             704 :         if (!bResumeLine)
     184                 :         {
     185             704 :             papszTokens = CSLTokenizeString(pszLine);
     186             704 :             nTokens = CSLCount(papszTokens);
     187             704 :             nLineNumber ++;
     188             704 :             bResumeLine = FALSE;
     189                 :         }
     190                 : 
     191             749 :         do
     192                 :         {
     193             761 :             bResumeLine = FALSE;
     194                 : 
     195             761 :             if (nTokens == 1 && strcmp(papszTokens[0], "99") == 0)
     196                 :             {
     197               1 :                 CSLDestroy(papszTokens);
     198               1 :                 papszTokens = NULL;
     199               1 :                 bEOF = TRUE;
     200               1 :                 if (bAptHeaderFound)
     201                 :                 {
     202               1 :                     if (poAPTLayer)
     203                 :                     {
     204                 :                         poAPTLayer->AddFeature(osAptICAO, osAptName, dfElevation,
     205                 :                                             bTowerFound || bRunwayFound,
     206                 :                                             (bTowerFound) ? dfLatTower : dfLatFirstRwy,
     207                 :                                             (bTowerFound) ? dfLonTower : dfLonFirstRwy, 
     208               1 :                                             bTowerFound, dfHeightTower, osTowerName);
     209                 :                     }
     210                 :                 }
     211               1 :                 return;
     212                 :             }
     213             760 :             else if (nTokens == 0 || assertMinCol(2) == FALSE)
     214                 :             {
     215              11 :                 break;
     216                 :             }
     217                 : 
     218             749 :             nType = atoi(papszTokens[0]);
     219             749 :             switch(nType)
     220                 :             {
     221                 :                 case APT_AIRPORT_HEADER:
     222               8 :                     if (bAptHeaderFound)
     223                 :                     {
     224               7 :                         bAptHeaderFound = FALSE;
     225               7 :                         if (poAPTLayer)
     226                 :                         {
     227                 :                             poAPTLayer->AddFeature(osAptICAO, osAptName, dfElevation,
     228                 :                                                     bTowerFound || bRunwayFound,
     229                 :                                                     (bTowerFound) ? dfLatTower : dfLatFirstRwy,
     230                 :                                                     (bTowerFound) ? dfLonTower : dfLonFirstRwy, 
     231               7 :                                                     bTowerFound, dfHeightTower, osTowerName);
     232                 :                         }
     233                 :                     }
     234               8 :                     ParseAptHeaderRecord();
     235               8 :                     break;
     236                 : 
     237                 :                 case APT_RUNWAY_TAXIWAY_V_810:
     238             441 :                     if (poAPTLayer ||
     239                 :                         poRunwayLayer || poRunwayThresholdLayer ||
     240                 :                         poStopwayLayer ||
     241                 :                         poHelipadLayer || poHelipadPolygonLayer ||
     242                 :                         poVASI_PAPI_WIGWAG_Layer || poTaxiwayRectangleLayer)
     243                 :                     {
     244             441 :                         ParseRunwayTaxiwayV810Record();
     245                 :                     }
     246             441 :                     break;
     247                 : 
     248                 :                 case APT_TOWER:
     249               4 :                     if (poAPTLayer)
     250               4 :                         ParseTowerRecord();
     251               4 :                     break;
     252                 : 
     253                 :                 case APT_STARTUP_LOCATION:
     254             110 :                     if (poStartupLocationLayer)
     255             110 :                         ParseStartupLocationRecord();
     256             110 :                     break;
     257                 : 
     258                 :                 case APT_LIGHT_BEACONS:
     259               3 :                     if (poAPTLightBeaconLayer)
     260               3 :                         ParseLightBeaconRecord();
     261               3 :                     break;
     262                 : 
     263                 :                 case APT_WINDSOCKS:
     264              25 :                     if (poAPTWindsockLayer)
     265              25 :                         ParseWindsockRecord();
     266              25 :                     break;
     267                 : 
     268                 :                 case APT_TAXIWAY_SIGNS:
     269              17 :                     if (poTaxiwaySignLayer)
     270              17 :                         ParseTaxiwaySignRecord();
     271              17 :                     break;
     272                 : 
     273                 :                 case APT_VASI_PAPI_WIGWAG:
     274              24 :                     if (poVASI_PAPI_WIGWAG_Layer)
     275              24 :                         ParseVasiPapiWigWagRecord();
     276              24 :                     break;
     277                 : 
     278                 :                 case APT_ATC_AWOS_ASOS_ATIS:
     279                 :                 case APT_ATC_CTAF:
     280                 :                 case APT_ATC_CLD:
     281                 :                 case APT_ATC_GND:
     282                 :                 case APT_ATC_TWR:
     283                 :                 case APT_ATC_APP:
     284                 :                 case APT_ATC_DEP:
     285              42 :                     if (poATCFreqLayer)
     286              42 :                         ParseATCRecord(nType);
     287              42 :                     break;
     288                 : 
     289                 :                 case APT_RUNWAY:
     290              16 :                     if (poAPTLayer || poRunwayLayer || poRunwayThresholdLayer || poStopwayLayer)
     291              16 :                         ParseRunwayRecord();
     292              16 :                     break;
     293                 : 
     294                 :                 case APT_WATER_RUNWAY:
     295               1 :                     if (poWaterRunwayLayer || poWaterRunwayThresholdLayer)
     296               1 :                         ParseWaterRunwayRecord();
     297               1 :                     break;
     298                 : 
     299                 :                 case APT_HELIPAD:
     300               1 :                     if (poHelipadLayer || poHelipadPolygonLayer)
     301               1 :                         ParseHelipadRecord();
     302               1 :                     break;
     303                 : 
     304                 :                 case APT_PAVEMENT_HEADER:
     305              11 :                     if (poPavementLayer)
     306              11 :                         ParsePavement();
     307              11 :                     break;
     308                 : 
     309                 :                 case APT_LINEAR_HEADER:
     310              45 :                     if (poAPTLinearFeatureLayer)
     311              45 :                         ParseAPTLinearFeature();
     312              45 :                     break;
     313                 : 
     314                 :                 case APT_BOUNDARY_HEADER:
     315               1 :                     if (poAPTBoundaryLayer)
     316               1 :                         ParseAPTBoundary();
     317                 :                     break;
     318                 : 
     319                 :                 default:
     320                 :                     break;
     321                 :             }
     322                 :         } while(bResumeLine);
     323                 : 
     324             703 :         CSLDestroy(papszTokens);
     325             703 :         papszTokens = NULL;
     326                 : 
     327             703 :         if (poInterestLayer && poInterestLayer->IsEmpty() == FALSE)
     328               0 :             return;
     329                 :     }
     330                 : 
     331               0 :     bEOF = TRUE;
     332                 : }
     333                 : 
     334                 : 
     335                 : /************************************************************************/
     336                 : /*                         ParseAptHeaderRecord()                       */
     337                 : /************************************************************************/
     338                 : 
     339               8 : void    OGRXPlaneAptReader::ParseAptHeaderRecord()
     340                 : {
     341               8 :     bAptHeaderFound = FALSE;
     342               8 :     bTowerFound = FALSE;
     343               8 :     bRunwayFound = FALSE;
     344                 : 
     345               8 :     RET_IF_FAIL(assertMinCol(6));
     346                 : 
     347                 :     /* feet to meter */
     348               8 :     RET_IF_FAIL(readDoubleWithBoundsAndConversion(&dfElevation, 1, "elevation", FEET_TO_METER, -1000., 10000.));
     349               8 :     bControlTower = atoi(papszTokens[2]);
     350                 :     // papszTokens[3] ignored
     351               8 :     osAptICAO = papszTokens[4];
     352              16 :     osAptName = readStringUntilEnd(5);
     353                 : 
     354               8 :     bAptHeaderFound = TRUE;
     355                 : }
     356                 : 
     357                 : /************************************************************************/
     358                 : /*                    ParseRunwayTaxiwayV810Record()                    */
     359                 : /************************************************************************/
     360                 : 
     361             441 : void    OGRXPlaneAptReader::ParseRunwayTaxiwayV810Record()
     362                 : {
     363                 :     double dfLat, dfLon, dfTrueHeading, dfLength, dfWidth;
     364                 :     double adfDisplacedThresholdLength[2];
     365                 :     double adfStopwayLength[2];
     366                 :     const char* pszRwyNum;
     367                 :     int aeVisualApproachLightingCode[2], aeRunwayLightingCode[2], aeApproachLightingCode[2];
     368                 :     int eSurfaceCode, eShoulderCode, eMarkings;
     369                 :     double dfSmoothness;
     370                 :     double adfVisualGlidePathAngle[2];
     371                 :     int bHasDistanceRemainingSigns;
     372                 : 
     373             441 :     RET_IF_FAIL(assertMinCol(15));
     374                 : 
     375             441 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
     376             441 :     pszRwyNum = papszTokens[3];
     377             441 :     RET_IF_FAIL(readTrueHeading(&dfTrueHeading, 4));
     378             441 :     RET_IF_FAIL(readDouble(&dfLength, 5, "length"));
     379             441 :     dfLength *= FEET_TO_METER;
     380             441 :     adfDisplacedThresholdLength[0] = atoi(papszTokens[6]) * FEET_TO_METER;
     381             441 :     if (strchr(papszTokens[6], '.') != NULL)
     382             441 :         adfDisplacedThresholdLength[1] = atoi(strchr(papszTokens[6], '.') + 1) * FEET_TO_METER;
     383             441 :     adfStopwayLength[0] = atoi(papszTokens[7]) * FEET_TO_METER;
     384             441 :     if (strchr(papszTokens[7], '.') != NULL)
     385             441 :         adfStopwayLength[1] = atoi(strchr(papszTokens[7], '.') + 1) * FEET_TO_METER;
     386             441 :     RET_IF_FAIL(readDouble(&dfWidth, 8, "width"));
     387             441 :     dfWidth *= FEET_TO_METER;
     388             441 :     if (strlen(papszTokens[9]) == 6)
     389                 :     {
     390             441 :         aeVisualApproachLightingCode[0] = papszTokens[9][0] - '0';
     391             441 :         aeRunwayLightingCode[0] = papszTokens[9][1] - '0';
     392             441 :         aeApproachLightingCode[0] = papszTokens[9][2] - '0';
     393             441 :         aeVisualApproachLightingCode[1] = papszTokens[9][3] - '0';
     394             441 :         aeRunwayLightingCode[1] = papszTokens[9][4] - '0';
     395             441 :         aeApproachLightingCode[1] = papszTokens[9][5] - '0';
     396                 :     }
     397             441 :     eSurfaceCode = atoi(papszTokens[10]);
     398             441 :     eShoulderCode = atoi(papszTokens[11]);
     399             441 :     eMarkings = atoi(papszTokens[12]);
     400             441 :     RET_IF_FAIL(readDoubleWithBounds(&dfSmoothness, 13, "runway smoothness", 0., 1.));
     401             441 :     bHasDistanceRemainingSigns = atoi(papszTokens[14]);
     402             441 :     if (nTokens == 16)
     403                 :     {
     404               4 :         adfVisualGlidePathAngle[0] = atoi(papszTokens[15]) / 100.;
     405               4 :         if (strchr(papszTokens[15], '.') != NULL)
     406               4 :             adfVisualGlidePathAngle[1] = atoi(strchr(papszTokens[15], '.') + 1) / 100.;
     407                 :     }
     408                 : 
     409             441 :     if (strcmp(pszRwyNum, "xxx") == 000)
     410                 :     {
     411                 :         /* Taxiway */
     412             437 :         if (poTaxiwayRectangleLayer)
     413                 :             poTaxiwayRectangleLayer->AddFeature(osAptICAO, dfLat, dfLon,
     414                 :                                     dfTrueHeading, dfLength, dfWidth,
     415                 :                                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     416             437 :                                     dfSmoothness, aeRunwayLightingCode[0] == 1);
     417                 :     }
     418               7 :     else if (pszRwyNum[0] >= '0' && pszRwyNum[0] <= '9' && strlen(pszRwyNum) >= 2)
     419                 :     {
     420                 :         /* Runway */
     421                 :         double adfLat[2], adfLon[2];
     422               3 :         CPLString aosRwyNum[2];
     423                 :         OGRFeature* poFeature;
     424                 :         int abReil[2];
     425                 : 
     426               3 :         int num1 = atoi(pszRwyNum);
     427               3 :         int num2 = (num1 > 18) ? num1 - 18 : num1 + 18;
     428               5 :         if (pszRwyNum[2] == '0' || pszRwyNum[2] == 'x')
     429                 :         {
     430               2 :             aosRwyNum[0].Printf("%02d", num1);
     431               2 :             aosRwyNum[1].Printf("%02d", num2);
     432                 :         }
     433                 :         else
     434                 :         {
     435               1 :             aosRwyNum[0] = pszRwyNum;
     436                 :             aosRwyNum[1].Printf("%02d%c", num2,
     437                 :                                 (aosRwyNum[0][2] == 'L') ? 'R' :
     438               1 :                                 (aosRwyNum[0][2] == 'R') ? 'L' : aosRwyNum[0][2]);
     439                 :         }
     440                 : 
     441               3 :         OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading + 180, &adfLat[0], &adfLon[0]);
     442               3 :         OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading, &adfLat[1], &adfLon[1]);
     443                 : 
     444               9 :         for(int i=0;i<2;i++)
     445               6 :             abReil[i] = (aeRunwayLightingCode[i] >= 3 && aeRunwayLightingCode[i] <= 5) ;
     446                 : 
     447               3 :         if (!bRunwayFound)
     448                 :         {
     449               1 :             dfLatFirstRwy = adfLat[0];
     450               1 :             dfLonFirstRwy = adfLon[0];
     451               1 :             bRunwayFound = TRUE;
     452                 :         }
     453                 : 
     454               3 :         if (poRunwayThresholdLayer)
     455                 :         {
     456               9 :             for(int i=0;i<2;i++)
     457                 :             {
     458                 :                 poFeature =
     459                 :                     poRunwayThresholdLayer->AddFeature  
     460               6 :                         (osAptICAO, aosRwyNum[i],
     461                 :                         adfLat[i], adfLon[i], dfWidth,
     462                 :                         RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     463                 :                         RunwayShoulderEnumeration.GetText(eShoulderCode),
     464                 :                         dfSmoothness,
     465              12 :                         (aeRunwayLightingCode[i] == 4 || aeRunwayLightingCode[i] == 5) /* bHasCenterLineLights */,
     466              10 :                         (aeRunwayLightingCode[i] >= 2 && aeRunwayLightingCode[i] <= 5) ? "Yes" : "None" /* pszEdgeLighting */,
     467                 :                         bHasDistanceRemainingSigns,
     468                 :                         adfDisplacedThresholdLength[i], adfStopwayLength[i],
     469                 :                         RunwayMarkingEnumeration.GetText(eMarkings),
     470                 :                         RunwayApproachLightingEnumerationV810.GetText(aeApproachLightingCode[i]),
     471               6 :                         (aeRunwayLightingCode[i] == 5) /* bHasTouchdownLights */,
     472               8 :                         (abReil[i] && abReil[i]) ? "Omni-directional" :
     473              42 :                         (abReil[i] && !abReil[1-i]) ? "Unidirectional" : "None" /* eReil */);
     474                 :                 poRunwayThresholdLayer->SetRunwayLengthAndHeading(poFeature, dfLength,
     475               6 :                         (i == 0) ? dfTrueHeading : (dfTrueHeading < 180) ? dfTrueHeading + 180 : dfTrueHeading - 180);
     476               6 :                 if (adfDisplacedThresholdLength[i] != 0)
     477               1 :                     poRunwayThresholdLayer->AddFeatureFromNonDisplacedThreshold(poFeature);
     478                 :             }
     479                 :         }
     480                 : 
     481               3 :         if (poRunwayLayer)
     482                 :         {
     483                 :             poRunwayLayer->AddFeature(osAptICAO, aosRwyNum[0], aosRwyNum[1],
     484                 :                                     adfLat[0], adfLon[0], adfLat[1], adfLon[1],
     485                 :                                     dfWidth,
     486                 :                                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     487                 :                                     RunwayShoulderEnumeration.GetText(eShoulderCode),
     488                 :                                     dfSmoothness,
     489               6 :                                     (aeRunwayLightingCode[0] == 4 || aeRunwayLightingCode[0] == 5),
     490               5 :                                     (aeRunwayLightingCode[0] >= 2 && aeRunwayLightingCode[0] <= 5) ? "Yes" : "None" /* pszEdgeLighting */,
     491              11 :                                     bHasDistanceRemainingSigns);
     492                 :         }
     493                 :         
     494               3 :         if (poStopwayLayer)
     495                 :         {
     496               9 :             for(int i=0;i<2;i++)
     497                 :             {
     498               6 :                 if (adfStopwayLength[i] != 0)
     499                 :                 {
     500                 :                     double dfHeading = OGRXPlane_Track(adfLat[i], adfLon[i],
     501               0 :                                                        adfLat[1-i], adfLon[1-i]);
     502               0 :                     poStopwayLayer->AddFeature(osAptICAO, aosRwyNum[i],
     503               0 :                         adfLat[i], adfLon[i], dfHeading, dfWidth, adfStopwayLength[i]);
     504                 :                 }
     505                 :             }
     506                 :         }
     507                 : 
     508               3 :         if (poVASI_PAPI_WIGWAG_Layer)
     509                 :         {
     510               9 :             for(int i=0;i<2;i++)
     511                 :             {
     512               6 :                 if (aeApproachLightingCode[i])
     513               6 :                     poVASI_PAPI_WIGWAG_Layer->AddFeature(osAptICAO, aosRwyNum[i],
     514                 :                             RunwayVisualApproachPathIndicatorEnumerationV810.GetText(aeApproachLightingCode[i]),
     515                 :                             adfLat[i], adfLon[i],
     516                 :                             (i == 0) ? dfTrueHeading : (dfTrueHeading < 180) ? dfTrueHeading + 180 : dfTrueHeading- 180,
     517              12 :                              adfVisualGlidePathAngle[i]);
     518                 :             }
     519               3 :         }
     520                 :     }
     521               1 :     else if (pszRwyNum[0] == 'H')
     522                 :     {
     523                 :         /* Helipad */
     524               1 :         CPLString osHelipadName = pszRwyNum;
     525               1 :         if (strlen(pszRwyNum) == 3 && pszRwyNum[2] == 'x')
     526               1 :             osHelipadName[2] = 0;
     527                 : 
     528               1 :         if (poHelipadLayer)
     529                 :         {
     530                 :             poHelipadLayer->AddFeature(osAptICAO, osHelipadName, dfLat, dfLon,
     531                 :                                     dfTrueHeading, dfLength, dfWidth,
     532                 :                                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     533                 :                                     RunwayMarkingEnumeration.GetText(eMarkings),
     534                 :                                     RunwayShoulderEnumeration.GetText(eShoulderCode),
     535                 :                                     dfSmoothness,
     536               1 :                                     (aeRunwayLightingCode[0] >= 2 && aeRunwayLightingCode[0] <= 5) ? "Yes" : "None" /* pszEdgeLighting */);
     537                 :         }
     538                 : 
     539               1 :         if (poHelipadPolygonLayer)
     540                 :         {
     541                 :             poHelipadPolygonLayer->AddFeature(osAptICAO, osHelipadName, dfLat, dfLon,
     542                 :                                     dfTrueHeading, dfLength, dfWidth,
     543                 :                                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     544                 :                                     RunwayMarkingEnumeration.GetText(eMarkings),
     545                 :                                     RunwayShoulderEnumeration.GetText(eShoulderCode),
     546                 :                                     dfSmoothness,
     547               1 :                                     (aeRunwayLightingCode[0] >= 2 && aeRunwayLightingCode[0] <= 5) ? "Yes" : "None" /* pszEdgeLighting */);
     548               1 :         }
     549                 :     }
     550                 :     else
     551                 :     {
     552                 :         CPLDebug("XPlane", "Line %d : Unexpected runway number : %s",
     553               0 :                     nLineNumber, pszRwyNum);
     554                 :     }
     555                 : 
     556                 : }
     557                 : 
     558                 : /************************************************************************/
     559                 : /*                        ParseRunwayRecord()                           */
     560                 : /************************************************************************/
     561                 : 
     562              16 : void OGRXPlaneAptReader::ParseRunwayRecord()
     563                 : {
     564                 :     double dfWidth;
     565                 :     int eSurfaceCode, eShoulderCode;
     566                 :     double dfSmoothness;
     567                 :     int bHasCenterLineLights, bHasDistanceRemainingSigns;
     568                 :     int eEdgeLighting;
     569                 :     int nCurToken;
     570              16 :     int nRwy = 0;
     571                 :     double adfLat[2], adfLon[2];
     572              16 :     OGRFeature* apoRunwayThreshold[2] = { NULL, NULL };
     573                 :     double dfLength;
     574              16 :     CPLString aosRunwayId[2];
     575                 :     double adfDisplacedThresholdLength[2];
     576                 :     double adfStopwayLength[2];
     577                 : 
     578              32 :     RET_IF_FAIL(assertMinCol(8 + 9 + 9));
     579                 : 
     580              16 :     RET_IF_FAIL(readDouble(&dfWidth, 1, "runway width"));
     581              16 :     eSurfaceCode = atoi(papszTokens[2]);
     582              16 :     eShoulderCode = atoi(papszTokens[3]);
     583              16 :     RET_IF_FAIL(readDoubleWithBounds(&dfSmoothness, 4, "runway smoothness", 0., 1.));
     584              16 :     bHasCenterLineLights = atoi(papszTokens[5]);
     585              16 :     eEdgeLighting = atoi(papszTokens[6]);
     586              16 :     bHasDistanceRemainingSigns = atoi(papszTokens[7]);
     587                 : 
     588              48 :     for( nRwy=0, nCurToken = 8 ; nRwy<=1 ; nRwy++, nCurToken += 9 )
     589                 :     {
     590                 :         double dfLat, dfLon;
     591                 :         int eMarkings, eApproachLightingCode, eREIL;
     592                 :         int bHasTouchdownLights;
     593                 : 
     594              32 :         aosRunwayId[nRwy] = papszTokens[nCurToken + 0]; /* for example : 08, 24R, or xxx */
     595              32 :         RET_IF_FAIL(readLatLon(&dfLat, &dfLon, nCurToken + 1));
     596              32 :         adfLat[nRwy] = dfLat; 
     597              32 :         adfLon[nRwy] = dfLon;
     598              32 :         RET_IF_FAIL(readDouble(&adfDisplacedThresholdLength[nRwy], nCurToken + 3, "displaced threshold length"));
     599              32 :         RET_IF_FAIL(readDouble(&adfStopwayLength[nRwy], nCurToken + 4, "stopway/blastpad/over-run length"));
     600              32 :         eMarkings = atoi(papszTokens[nCurToken + 5]);
     601              32 :         eApproachLightingCode = atoi(papszTokens[nCurToken + 6]);
     602              32 :         bHasTouchdownLights = atoi(papszTokens[nCurToken + 7]);
     603              32 :         eREIL = atoi(papszTokens[nCurToken + 8]);
     604                 : 
     605              32 :         if (!bRunwayFound)
     606                 :         {
     607               7 :             dfLatFirstRwy = dfLat;
     608               7 :             dfLonFirstRwy = dfLon;
     609               7 :             bRunwayFound = TRUE;
     610                 :         }
     611                 : 
     612              32 :         if (poRunwayThresholdLayer)
     613                 :         {
     614              32 :             apoRunwayThreshold[nRwy] =
     615                 :                 poRunwayThresholdLayer->AddFeature  
     616              32 :                     (osAptICAO, aosRunwayId[nRwy],
     617                 :                     dfLat, dfLon, dfWidth,
     618                 :                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     619                 :                     RunwayShoulderEnumeration.GetText(eShoulderCode),
     620                 :                     dfSmoothness, bHasCenterLineLights,
     621                 :                     RunwayEdgeLightingEnumeration.GetText(eEdgeLighting), bHasDistanceRemainingSigns,
     622                 :                     adfDisplacedThresholdLength[nRwy], adfStopwayLength[nRwy],
     623                 :                     RunwayMarkingEnumeration.GetText(eMarkings),
     624                 :                     RunwayApproachLightingEnumeration.GetText(eApproachLightingCode),
     625                 :                     bHasTouchdownLights,
     626              64 :                     RunwayREILEnumeration.GetText(eREIL));
     627                 :         }
     628                 :     }
     629                 : 
     630              16 :     dfLength = OGRXPlane_Distance(adfLat[0], adfLon[0], adfLat[1], adfLon[1]);
     631              16 :     if (poRunwayThresholdLayer)
     632                 :     {
     633                 :         poRunwayThresholdLayer->SetRunwayLengthAndHeading(apoRunwayThreshold[0], dfLength,
     634              16 :                                     OGRXPlane_Track(adfLat[0], adfLon[0], adfLat[1], adfLon[1]));
     635                 :         poRunwayThresholdLayer->SetRunwayLengthAndHeading(apoRunwayThreshold[1], dfLength,
     636              16 :                                     OGRXPlane_Track(adfLat[1], adfLon[1], adfLat[0], adfLon[0]));
     637              16 :         if (adfDisplacedThresholdLength[0] != 0)
     638               1 :             poRunwayThresholdLayer->AddFeatureFromNonDisplacedThreshold(apoRunwayThreshold[0]);
     639              16 :         if (adfDisplacedThresholdLength[1] != 0)
     640               4 :             poRunwayThresholdLayer->AddFeatureFromNonDisplacedThreshold(apoRunwayThreshold[1]);
     641                 :     }
     642                 : 
     643              16 :     if (poRunwayLayer)
     644                 :     {
     645                 :         poRunwayLayer->AddFeature(osAptICAO, aosRunwayId[0], aosRunwayId[1],
     646                 :                                     adfLat[0], adfLon[0], adfLat[1], adfLon[1],
     647                 :                                     dfWidth,
     648                 :                                     RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     649                 :                                     RunwayShoulderEnumeration.GetText(eShoulderCode),
     650                 :                                     dfSmoothness, bHasCenterLineLights,
     651                 :                                     RunwayEdgeLightingEnumeration.GetText(eEdgeLighting),
     652              16 :                                     bHasDistanceRemainingSigns);
     653                 :     }
     654                 :             
     655              16 :     if (poStopwayLayer)
     656                 :     {
     657              48 :         for(int i=0;i<2;i++)
     658                 :         {
     659              32 :             if (adfStopwayLength[i] != 0)
     660                 :             {
     661                 :                 double dfHeading = OGRXPlane_Track(adfLat[i], adfLon[i],
     662               6 :                                                    adfLat[1-i], adfLon[1-i]);
     663               6 :                 poStopwayLayer->AddFeature(osAptICAO, aosRunwayId[i],
     664              12 :                     adfLat[i], adfLon[i], dfHeading, dfWidth, adfStopwayLength[i]);
     665                 :             }
     666                 :         }
     667               0 :     }
     668                 : }
     669                 : 
     670                 : /************************************************************************/
     671                 : /*                       ParseWaterRunwayRecord()                       */
     672                 : /************************************************************************/
     673                 : 
     674               1 : void OGRXPlaneAptReader::ParseWaterRunwayRecord()
     675                 : {
     676                 :     double adfLat[2], adfLon[2];
     677               1 :     OGRFeature* apoWaterRunwayThreshold[2] = {NULL, NULL};
     678                 :     double dfWidth, dfLength;
     679                 :     int bBuoys;
     680               1 :     CPLString aosRunwayId[2];
     681                 :     int i;
     682                 : 
     683               2 :     RET_IF_FAIL(assertMinCol(9));
     684                 : 
     685               1 :     RET_IF_FAIL(readDouble(&dfWidth, 1, "runway width"));
     686               1 :     bBuoys = atoi(papszTokens[2]);
     687                 : 
     688               3 :     for(i=0;i<2;i++)
     689                 :     {
     690               2 :         aosRunwayId[i] = papszTokens[3 + 3*i];
     691               2 :         RET_IF_FAIL(readLatLon(&adfLat[i], &adfLon[i], 4 + 3*i));
     692                 : 
     693               2 :         if (poWaterRunwayThresholdLayer)
     694                 :         {
     695               2 :             apoWaterRunwayThreshold[i] =
     696                 :                 poWaterRunwayThresholdLayer->AddFeature  
     697               2 :                     (osAptICAO, aosRunwayId[i], adfLat[i], adfLon[i], dfWidth, bBuoys);
     698                 :         }
     699                 : 
     700                 :     }
     701                 : 
     702               1 :     dfLength = OGRXPlane_Distance(adfLat[0], adfLon[0], adfLat[1], adfLon[1]);
     703                 : 
     704               1 :     if (poWaterRunwayThresholdLayer)
     705                 :     {
     706                 :         poWaterRunwayThresholdLayer->SetRunwayLengthAndHeading(apoWaterRunwayThreshold[0], dfLength,
     707               1 :                                     OGRXPlane_Track(adfLat[0], adfLon[0], adfLat[1], adfLon[1]));
     708                 :         poWaterRunwayThresholdLayer->SetRunwayLengthAndHeading(apoWaterRunwayThreshold[1], dfLength,
     709               1 :                                     OGRXPlane_Track(adfLat[1], adfLon[1], adfLat[0], adfLon[0]));
     710                 :     }
     711                 : 
     712               1 :     if (poWaterRunwayLayer)
     713                 :     {
     714                 :         poWaterRunwayLayer->AddFeature(osAptICAO, aosRunwayId[0], aosRunwayId[1],
     715                 :                                     adfLat[0], adfLon[0], adfLat[1], adfLon[1],
     716               1 :                                     dfWidth, bBuoys);
     717               0 :     }
     718                 : }
     719                 : 
     720                 : /************************************************************************/
     721                 : /*                       ParseHelipadRecord()                           */
     722                 : /************************************************************************/
     723                 : 
     724               1 : void OGRXPlaneAptReader::ParseHelipadRecord()
     725                 : {
     726                 :     double dfLat, dfLon, dfTrueHeading, dfLength, dfWidth, dfSmoothness;
     727                 :     int eSurfaceCode, eMarkings, eShoulderCode, eEdgeLighting;
     728                 :     const char* pszHelipadName;
     729                 : 
     730               1 :     RET_IF_FAIL(assertMinCol(12));
     731                 : 
     732               1 :     pszHelipadName = papszTokens[1];
     733               1 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 2));
     734               1 :     RET_IF_FAIL(readTrueHeading(&dfTrueHeading, 4));
     735               1 :     RET_IF_FAIL(readDouble(&dfLength, 5, "length"));
     736               1 :     RET_IF_FAIL(readDouble(&dfWidth, 6, "width"));
     737               1 :     eSurfaceCode = atoi(papszTokens[7]);
     738               1 :     eMarkings = atoi(papszTokens[8]);
     739               1 :     eShoulderCode = atoi(papszTokens[9]);
     740               1 :     RET_IF_FAIL(readDoubleWithBounds(&dfSmoothness, 10, "helipad smoothness", 0., 1.));
     741               1 :     eEdgeLighting = atoi(papszTokens[11]);
     742                 : 
     743               1 :     if (poHelipadLayer)
     744                 :     {
     745                 :         poHelipadLayer->AddFeature(osAptICAO, pszHelipadName, dfLat, dfLon,
     746                 :                                 dfTrueHeading, dfLength, dfWidth,
     747                 :                                 RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     748                 :                                 RunwayMarkingEnumeration.GetText(eMarkings),
     749                 :                                 RunwayShoulderEnumeration.GetText(eShoulderCode),
     750                 :                                 dfSmoothness,
     751               1 :                                 HelipadEdgeLightingEnumeration.GetText(eEdgeLighting));
     752                 :     }
     753                 : 
     754               1 :     if (poHelipadPolygonLayer)
     755                 :     {
     756                 :         poHelipadPolygonLayer->AddFeature(osAptICAO, pszHelipadName, dfLat, dfLon,
     757                 :                                         dfTrueHeading, dfLength, dfWidth,
     758                 :                                         RunwaySurfaceEnumeration.GetText(eSurfaceCode),
     759                 :                                         RunwayMarkingEnumeration.GetText(eMarkings),
     760                 :                                         RunwayShoulderEnumeration.GetText(eShoulderCode),
     761                 :                                         dfSmoothness,
     762               1 :                                         HelipadEdgeLightingEnumeration.GetText(eEdgeLighting));
     763                 :     }
     764                 : }
     765                 : 
     766                 : 
     767                 : 
     768                 : /************************************************************************/
     769                 : /*                          AddBezierCurve()                           */
     770                 : /************************************************************************/
     771                 : 
     772                 : #define CUBIC_INTERPOL(A, B, C, D)  ((A)*(b*b*b) + 3*(B)*(b*b)*a + 3 *(C)*b*(a*a) + (D)*(a*a*a))
     773                 : 
     774             239 : void OGRXPlaneAptReader::AddBezierCurve(OGRLineString& lineString,
     775                 :                                         double dfLatA, double dfLonA,
     776                 :                                         double dfCtrPtLatA, double dfCtrPtLonA,
     777                 :                                         double dfSymCtrlPtLatB, double dfSymCtrlPtLonB,
     778                 :                                         double dfLatB, double dfLonB)
     779                 : {
     780                 :     int step;
     781            2868 :     for(step = 0; step <= 10; step++)
     782                 :     {
     783            2629 :         double a = step / 10.;
     784            2629 :         double b = 1. - a;
     785            2629 :         double dfCtrlPtLonB = dfLonB - (dfSymCtrlPtLonB - dfLonB);
     786            2629 :         double dfCtrlPtLatB = dfLatB - (dfSymCtrlPtLatB - dfLatB);
     787                 :         lineString.addPoint(CUBIC_INTERPOL(dfLonA, dfCtrPtLonA, dfCtrlPtLonB, dfLonB),
     788            2629 :                             CUBIC_INTERPOL(dfLatA, dfCtrPtLatA, dfCtrlPtLatB, dfLatB));
     789                 :     }
     790             239 : }
     791                 : 
     792                 : 
     793                 : #define QUADRATIC_INTERPOL(A, B, C)  ((A)*(b*b) + 2*(B)*b*a + (C)*(a*a))
     794                 : 
     795              89 : void OGRXPlaneAptReader::AddBezierCurve(OGRLineString& lineString,
     796                 :                                         double dfLatA, double dfLonA,
     797                 :                                         double dfCtrPtLat, double dfCtrPtLon,
     798                 :                                         double dfLatB, double dfLonB)
     799                 : {
     800                 :     int step;
     801            1068 :     for(step = 0; step <= 10; step++)
     802                 :     {
     803             979 :         double a = step / 10.;
     804             979 :         double b = 1. - a;
     805                 :         lineString.addPoint(QUADRATIC_INTERPOL(dfLonA, dfCtrPtLon, dfLonB),
     806             979 :                             QUADRATIC_INTERPOL(dfLatA, dfCtrPtLat, dfLatB));
     807                 :     }
     808              89 : }
     809                 : 
     810               2 : static OGRGeometry* OGRXPlaneAptReaderSplitPolygon(OGRPolygon& polygon)
     811                 : {
     812               2 :     OGRPolygon** papoPolygons = new OGRPolygon* [1 + polygon.getNumInteriorRings()];
     813                 : 
     814               2 :     papoPolygons[0] = new OGRPolygon();
     815               2 :     papoPolygons[0]->addRing(polygon.getExteriorRing());
     816              12 :     for(int i=0;i<polygon.getNumInteriorRings();i++)
     817                 :     {
     818               4 :         papoPolygons[i+1] = new OGRPolygon();
     819               4 :         papoPolygons[i+1]->addRing(polygon.getInteriorRing(i));
     820                 :     }
     821                 : 
     822                 :     int bIsValid;
     823                 :     OGRGeometry* poGeom;
     824                 :     poGeom = OGRGeometryFactory::organizePolygons((OGRGeometry**)papoPolygons,
     825                 :                                                   1 + polygon.getNumInteriorRings(),
     826               2 :                                                   &bIsValid, NULL);
     827                 : 
     828               2 :     delete[] papoPolygons;
     829                 : 
     830               2 :     return poGeom;
     831                 : }
     832                 : 
     833                 : /************************************************************************/
     834                 : /*                           FixPolygonTopology()                       */
     835                 : /************************************************************************/
     836                 : 
     837                 : /*
     838                 : Intended to fix several topological problems, like when a point of an interior ring
     839                 : is on the edge of the external ring, or other topological anomalies.
     840                 : */
     841                 : 
     842              12 : OGRGeometry* OGRXPlaneAptReader::FixPolygonTopology(OGRPolygon& polygon)
     843                 : {
     844              12 :     OGRLinearRing* poExternalRing = polygon.getExteriorRing();
     845              12 :     if (poExternalRing->getNumPoints() < 4)
     846                 :     {
     847               0 :         CPLDebug("XPLANE", "Discarded degenerated polygon at line %d", nLineNumber);
     848               0 :         return NULL;
     849                 :     }
     850                 :         
     851              12 :     for(int i=0;i<polygon.getNumInteriorRings();i++)
     852                 :     {
     853               2 :         OGRLinearRing* poInternalRing = polygon.getInteriorRing(i);
     854               2 :         if (poInternalRing->getNumPoints() < 4)
     855                 :         {
     856               0 :             CPLDebug("XPLANE", "Discarded degenerated interior ring (%d) at line %d", i, nLineNumber);
     857               0 :             OGRPolygon polygon2;
     858               0 :             polygon2.addRing(poExternalRing);
     859               0 :             for(int j=0;j<polygon.getNumInteriorRings();j++)
     860                 :             {
     861               0 :                 if (i != j)
     862               0 :                     polygon2.addRing(polygon.getInteriorRing(j));
     863                 :             }
     864               0 :             polygon = * (OGRPolygon*) (polygon2.clone());
     865               0 :             i --;
     866               0 :             continue;
     867                 :         }
     868                 :         
     869               2 :         int nOutside = 0;
     870               2 :         int jOutside = -1;
     871             101 :         for(int j=0;j<poInternalRing->getNumPoints();j++)
     872                 :         {
     873              99 :             OGRPoint pt;
     874              99 :             poInternalRing->getPoint(j, &pt);
     875              99 :             if (poExternalRing->isPointInRing(&pt) == FALSE)
     876                 :             {
     877               0 :                 nOutside++;
     878               0 :                 jOutside = j;
     879                 :             }
     880                 :         }
     881                 : 
     882               2 :         if (nOutside == 1)
     883                 :         {
     884               0 :             int j = jOutside;
     885               0 :             OGRPoint pt;
     886               0 :             poInternalRing->getPoint(j, &pt);
     887               0 :             OGRPoint newPt;
     888               0 :             int bSuccess = FALSE;
     889               0 :             for(int k=-1;k<=1 && !bSuccess;k+=2)
     890                 :             {
     891               0 :                 for(int l=-1;l<=1 && !bSuccess;l+=2)
     892                 :                 {
     893               0 :                     newPt.setX(pt.getX() + k * 1e-7);
     894               0 :                     newPt.setY(pt.getY() + l * 1e-7);
     895               0 :                     if (poExternalRing->isPointInRing(&newPt))
     896                 :                     {
     897               0 :                         poInternalRing->setPoint(j, newPt.getX(), newPt.getY());
     898               0 :                         bSuccess = TRUE;
     899                 :                     }
     900                 :                 }
     901                 :             }
     902               0 :             if (!bSuccess)
     903                 :             {
     904                 :                 CPLDebug("XPLANE",
     905               0 :                             "Didn't manage to fix polygon topology at line %d", nLineNumber);
     906                 : 
     907                 :                 /* Invalid topology. Will split into several pieces */
     908               0 :                 return OGRXPlaneAptReaderSplitPolygon(polygon);
     909               0 :             }
     910                 :         }
     911                 :         else
     912                 :         {
     913                 :             /* Two parts. Or other strange cases */
     914               2 :             return OGRXPlaneAptReaderSplitPolygon(polygon);
     915                 :         }
     916                 :     }
     917                 : 
     918                 :     /* The geometry is right */
     919              10 :     return polygon.clone();
     920                 : }
     921                 : 
     922                 : /************************************************************************/
     923                 : /*                         ParsePolygonalGeometry()                     */
     924                 : /************************************************************************/
     925                 : 
     926                 : /* This function will eat records until the end of the polygon */
     927                 : /* Return TRUE if the main parser must re-scan the current record */
     928                 : 
     929                 : #define RET_FALSE_IF_FAIL(x)      if (!(x)) return FALSE;
     930                 : 
     931              12 : int OGRXPlaneAptReader::ParsePolygonalGeometry(OGRGeometry** ppoGeom)
     932                 : {
     933                 :     double dfLat, dfLon;
     934              12 :     double dfFirstLat = 0., dfFirstLon = 0.;
     935              12 :     double dfLastLat = 0., dfLastLon = 0.;
     936                 :     double dfLatBezier, dfLonBezier;
     937              12 :     double dfFirstLatBezier = 0., dfFirstLonBezier = 0.;
     938              12 :     double dfLastLatBezier = 0., dfLastLonBezier = 0.;
     939              12 :     int bIsFirst = TRUE;
     940              12 :     int bFirstIsBezier = TRUE;
     941              12 :     int bLastIsValid = FALSE;
     942              12 :     int bLastIsBezier = FALSE;
     943              12 :     int bLastPartIsClosed = FALSE;
     944                 :     const char* pszLine;
     945              12 :     OGRPolygon polygon;
     946                 : 
     947              12 :     OGRLinearRing linearRing;
     948                 : 
     949              12 :     *ppoGeom = NULL;
     950                 : 
     951             400 :     while((pszLine = CPLReadLine(fp)) != NULL)
     952                 :     {
     953             388 :         int nType = -1;
     954             388 :         papszTokens = CSLTokenizeString(pszLine);
     955             388 :         nTokens = CSLCount(papszTokens);
     956                 : 
     957             388 :         nLineNumber ++;
     958                 : 
     959             388 :         if (nTokens == 1 && strcmp(papszTokens[0], "99") == 0)
     960                 :         {
     961               0 :             if (bLastPartIsClosed == FALSE)
     962                 :             {
     963                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a polygon : %d",
     964               0 :                         nLineNumber, nType);
     965                 :             }
     966                 :             else
     967                 :             {
     968               0 :                 *ppoGeom = FixPolygonTopology(polygon);
     969                 :             }
     970                 : 
     971               0 :             return TRUE;
     972                 :         }
     973             388 :         if (nTokens == 0 || assertMinCol(2) == FALSE)
     974                 :         {
     975               0 :             CSLDestroy(papszTokens);
     976               0 :             continue;
     977                 :         }
     978                 : 
     979             388 :         nType = atoi(papszTokens[0]);
     980             388 :         if (nType == APT_NODE)
     981                 :         {
     982             155 :             RET_FALSE_IF_FAIL(assertMinCol(3));
     983             155 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
     984                 : 
     985             198 :             if (bLastIsBezier && !bIsFirst &&
     986                 :                 !(dfLastLat == dfLat && dfLastLon == dfLon))
     987                 :             {
     988                 :                 AddBezierCurve(linearRing,
     989                 :                                dfLastLat, dfLastLon,
     990                 :                                dfLastLatBezier, dfLastLonBezier,
     991              43 :                                dfLat, dfLon);
     992                 :             }
     993                 :             else
     994             112 :                 linearRing.addPoint(dfLon, dfLat);
     995                 : 
     996             155 :             bLastPartIsClosed = FALSE;
     997             155 :             bLastIsBezier = FALSE;
     998                 :         }
     999             233 :         else if (nType == APT_NODE_WITH_BEZIER)
    1000                 :         {
    1001             205 :             RET_FALSE_IF_FAIL(assertMinCol(5));
    1002             205 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1003             205 :             RET_FALSE_IF_FAIL(readLatLon(&dfLatBezier, &dfLonBezier, 3));
    1004                 : 
    1005             205 :             if (bLastIsBezier)
    1006                 :             {
    1007                 :                 AddBezierCurve(linearRing,
    1008                 :                                dfLastLat, dfLastLon,
    1009                 :                                dfLastLatBezier, dfLastLonBezier,
    1010                 :                                dfLatBezier, dfLonBezier,
    1011             148 :                                dfLat, dfLon);
    1012                 :             }
    1013              57 :             else if (!bIsFirst && !(dfLastLat == dfLat && dfLastLon == dfLon))
    1014                 :             {
    1015              42 :                 double dfCtrLatBezier = dfLat - (dfLatBezier - dfLat);
    1016              42 :                 double dfCtrLonBezier = dfLon - (dfLonBezier - dfLon);
    1017                 :                 AddBezierCurve(linearRing,
    1018                 :                                dfLastLat, dfLastLon,
    1019                 :                                dfCtrLatBezier, dfCtrLonBezier,
    1020              42 :                                dfLat, dfLon);
    1021                 :             }
    1022                 : 
    1023             205 :             bLastPartIsClosed = FALSE;
    1024             205 :             bLastIsBezier = TRUE;
    1025             205 :             dfLastLatBezier = dfLatBezier;
    1026             205 :             dfLastLonBezier = dfLonBezier;
    1027                 :         }
    1028              28 :         else if (nType == APT_NODE_CLOSE)
    1029                 :         {
    1030               8 :             RET_FALSE_IF_FAIL(assertMinCol(3));
    1031               8 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1032               8 :             if (bIsFirst)
    1033                 :             {
    1034                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a polygon : %d",
    1035               0 :                         nLineNumber, nType);
    1036               0 :                 return TRUE;
    1037                 :             }
    1038                 : 
    1039               8 :             if (bLastIsBezier && !bIsFirst &&
    1040                 :                 !(dfLastLat == dfLat && dfLastLon == dfLon))
    1041                 :             {
    1042                 :                 AddBezierCurve(linearRing,
    1043                 :                                dfLastLat, dfLastLon,
    1044                 :                                dfLastLatBezier, dfLastLonBezier,
    1045               0 :                                dfLat, dfLon);
    1046                 :             }
    1047                 :             else
    1048               8 :                 linearRing.addPoint(dfLon, dfLat);
    1049                 : 
    1050               8 :             linearRing.closeRings();
    1051                 : 
    1052               8 :             polygon.addRing(&linearRing);
    1053               8 :             linearRing.empty();
    1054                 : 
    1055               8 :             bLastPartIsClosed = TRUE;
    1056               8 :             bLastIsBezier = FALSE;
    1057                 :         }
    1058              20 :         else if (nType == APT_NODE_CLOSE_WITH_BEZIER)
    1059                 :         {
    1060               8 :             RET_FALSE_IF_FAIL(assertMinCol(5));
    1061               8 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1062               8 :             RET_FALSE_IF_FAIL(readLatLon(&dfLatBezier, &dfLonBezier, 3));
    1063               8 :             if (bIsFirst)
    1064                 :             {
    1065                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a polygon : %d",
    1066               0 :                         nLineNumber, nType);
    1067               0 :                 return TRUE;
    1068                 :             }
    1069                 : 
    1070               8 :             if (bLastIsBezier)
    1071                 :             {
    1072                 :                 AddBezierCurve(linearRing,
    1073                 :                                dfLastLat, dfLastLon,
    1074                 :                                dfLastLatBezier, dfLastLonBezier,
    1075                 :                                dfLatBezier, dfLonBezier,
    1076               6 :                                dfLat, dfLon);
    1077                 :             }
    1078               3 :             else if (!bIsFirst && !(dfLastLat == dfLat && dfLastLon == dfLon))
    1079                 :             {
    1080               1 :                 double dfCtrLatBezier = dfLat - (dfLatBezier - dfLat);
    1081               1 :                 double dfCtrLonBezier = dfLon - (dfLonBezier - dfLon);
    1082                 :                 AddBezierCurve(linearRing,
    1083                 :                                dfLastLat, dfLastLon,
    1084                 :                                dfCtrLatBezier, dfCtrLonBezier,
    1085               1 :                                dfLat, dfLon);
    1086                 :             }
    1087                 :             else
    1088                 :             {
    1089               1 :                 linearRing.addPoint(dfLon, dfLat);
    1090                 :             }
    1091                 : 
    1092               8 :             if (bFirstIsBezier)
    1093                 :             {
    1094                 :                 AddBezierCurve(linearRing,
    1095                 :                                dfLat, dfLon,
    1096                 :                                dfLatBezier, dfLonBezier,
    1097                 :                                dfFirstLatBezier, dfFirstLonBezier,
    1098               6 :                                dfFirstLat, dfFirstLon);
    1099                 :             }
    1100                 :             else
    1101                 :             {
    1102               2 :                 linearRing.closeRings();
    1103                 :             }
    1104                 : 
    1105               8 :             polygon.addRing(&linearRing);
    1106               8 :             linearRing.empty();
    1107                 : 
    1108               8 :             bLastPartIsClosed = TRUE;
    1109               8 :             bLastIsBezier = FALSE; /* we don't want to draw an arc between two parts */
    1110                 :         }
    1111                 :         else
    1112                 :         {
    1113              12 :             if (nType == APT_NODE_END || nType == APT_NODE_END_WITH_BEZIER ||
    1114                 :                 bLastPartIsClosed == FALSE)
    1115                 :             {
    1116                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a polygon : %d",
    1117               0 :                         nLineNumber, nType);
    1118                 :             }
    1119                 :             else
    1120                 :             {
    1121              12 :                 *ppoGeom = FixPolygonTopology(polygon);
    1122                 :             }
    1123                 : 
    1124              12 :             return TRUE;
    1125                 :         }
    1126                 : 
    1127             376 :         if (bIsFirst)
    1128                 :         {
    1129              16 :             dfFirstLat = dfLat;
    1130              16 :             dfFirstLon = dfLon;
    1131              16 :             dfFirstLatBezier = dfLatBezier;
    1132              16 :             dfFirstLonBezier = dfLonBezier;
    1133              16 :             bFirstIsBezier = bLastIsBezier;
    1134                 :         }
    1135             376 :         bIsFirst = bLastPartIsClosed;
    1136                 : 
    1137             376 :         dfLastLat = dfLat;
    1138             376 :         dfLastLon = dfLon;
    1139             376 :         bLastIsValid = TRUE;
    1140                 : 
    1141             376 :         CSLDestroy(papszTokens);
    1142                 :     }
    1143                 : 
    1144                 :     CPLAssert(0);
    1145                 : 
    1146               0 :     papszTokens = NULL;
    1147                 : 
    1148               0 :     return FALSE;
    1149                 : }
    1150                 : 
    1151                 : 
    1152                 : /************************************************************************/
    1153                 : /*                            ParsePavement()                           */
    1154                 : /************************************************************************/
    1155                 : 
    1156              11 : void OGRXPlaneAptReader::ParsePavement()
    1157                 : {
    1158                 :     int eSurfaceCode;
    1159                 :     double dfSmoothness, dfTextureHeading;
    1160              11 :     CPLString osPavementName;
    1161                 : 
    1162              11 :     RET_IF_FAIL(assertMinCol(4));
    1163                 : 
    1164              11 :     eSurfaceCode = atoi(papszTokens[1]);
    1165                 : 
    1166              11 :     RET_IF_FAIL(readDoubleWithBounds(&dfSmoothness, 2, "pavement smoothness", 0., 1.));
    1167                 : 
    1168              11 :     RET_IF_FAIL(readTrueHeading(&dfTextureHeading, 3, "texture heading"));
    1169                 : 
    1170              11 :     osPavementName = readStringUntilEnd(4);
    1171                 : 
    1172              11 :     CSLDestroy(papszTokens);
    1173              11 :     papszTokens = NULL;
    1174                 : 
    1175                 :     OGRGeometry* poGeom;
    1176              11 :     bResumeLine = ParsePolygonalGeometry(&poGeom);
    1177              11 :     if (poGeom != NULL && poPavementLayer)
    1178                 :     {
    1179              11 :         if (poGeom->getGeometryType() == wkbPolygon)
    1180                 :         {
    1181                 :             poPavementLayer->AddFeature(osAptICAO, osPavementName,
    1182                 :                                         RunwaySurfaceEnumeration.GetText(eSurfaceCode),
    1183                 :                                         dfSmoothness, dfTextureHeading,
    1184              11 :                                         (OGRPolygon*)poGeom);
    1185                 :         }
    1186                 :         else
    1187                 :         {
    1188               0 :             OGRGeometryCollection* poGeomCollection = (OGRGeometryCollection*)poGeom;
    1189               0 :             for(int i=0;i<poGeomCollection->getNumGeometries();i++)
    1190                 :             {
    1191               0 :                 OGRGeometry* poSubGeom = poGeomCollection->getGeometryRef(i);
    1192               0 :                 if (poSubGeom->getGeometryType() == wkbPolygon &&
    1193                 :                     ((OGRPolygon*)poSubGeom)->getExteriorRing()->getNumPoints() >= 4)
    1194                 :                 {
    1195                 :                     poPavementLayer->AddFeature(osAptICAO, osPavementName,
    1196                 :                                                 RunwaySurfaceEnumeration.GetText(eSurfaceCode),
    1197                 :                                                 dfSmoothness, dfTextureHeading,
    1198               0 :                                                 (OGRPolygon*)poSubGeom);
    1199                 :                 }
    1200                 :             }
    1201                 :         }
    1202                 :     }
    1203              11 :     if (poGeom != NULL)
    1204              11 :         delete poGeom;
    1205                 : }
    1206                 : 
    1207                 : /************************************************************************/
    1208                 : /*                         ParseAPTBoundary()                           */
    1209                 : /************************************************************************/
    1210                 : 
    1211                 : /* This function will eat records until the end of the boundary definition */
    1212                 : /* Return TRUE if the main parser must re-scan the current record */
    1213                 : 
    1214               1 : void OGRXPlaneAptReader::ParseAPTBoundary()
    1215                 : {
    1216               1 :     CPLString osBoundaryName;
    1217                 : 
    1218               1 :     RET_IF_FAIL(assertMinCol(2));
    1219                 : 
    1220               1 :     osBoundaryName = readStringUntilEnd(2);
    1221                 : 
    1222               1 :     CSLDestroy(papszTokens);
    1223               1 :     papszTokens = NULL;
    1224                 : 
    1225                 :     OGRGeometry* poGeom;
    1226               1 :     bResumeLine = ParsePolygonalGeometry(&poGeom);
    1227               1 :     if (poGeom != NULL && poAPTBoundaryLayer)
    1228                 :     {
    1229               1 :         if (poGeom->getGeometryType() == wkbPolygon)
    1230                 :         {
    1231                 :              poAPTBoundaryLayer->AddFeature(osAptICAO, osBoundaryName,
    1232               1 :                                         (OGRPolygon*)poGeom);
    1233                 :         }
    1234                 :         else
    1235                 :         {
    1236               0 :             OGRGeometryCollection* poGeomCollection = (OGRGeometryCollection*)poGeom;
    1237               0 :             for(int i=0;i<poGeomCollection->getNumGeometries();i++)
    1238                 :             {
    1239               0 :                 OGRGeometry* poSubGeom = poGeomCollection->getGeometryRef(i);
    1240               0 :                 if (poSubGeom->getGeometryType() == wkbPolygon &&
    1241                 :                     ((OGRPolygon*)poSubGeom)->getExteriorRing()->getNumPoints() >= 4)
    1242                 :                 {
    1243                 :                     poAPTBoundaryLayer->AddFeature(osAptICAO, osBoundaryName,
    1244               0 :                                             (OGRPolygon*)poSubGeom);
    1245                 :                 }
    1246                 :             }
    1247                 :         }
    1248                 :     }
    1249               1 :     if (poGeom != NULL)
    1250               1 :         delete poGeom;
    1251                 : }
    1252                 : 
    1253                 : 
    1254                 : /************************************************************************/
    1255                 : /*                             ParseLinearGeometry()                    */
    1256                 : /************************************************************************/
    1257                 : 
    1258                 : /* This function will eat records until the end of the multilinestring */
    1259                 : /* Return TRUE if the main parser must re-scan the current record */
    1260                 : 
    1261              45 : int OGRXPlaneAptReader::ParseLinearGeometry(OGRMultiLineString& multilinestring, int* pbIsValid)
    1262                 : {
    1263                 :     double dfLat, dfLon;
    1264              45 :     double dfFirstLat = 0., dfFirstLon = 0.;
    1265              45 :     double dfLastLat = 0., dfLastLon = 0.;
    1266                 :     double dfLatBezier, dfLonBezier;
    1267              45 :     double dfFirstLatBezier = 0., dfFirstLonBezier = 0.;
    1268              45 :     double dfLastLatBezier = 0., dfLastLonBezier = 0.;
    1269              45 :     int bIsFirst = TRUE;
    1270              45 :     int bFirstIsBezier = TRUE;
    1271              45 :     int bLastIsValid = FALSE;
    1272              45 :     int bLastIsBezier = FALSE;
    1273              45 :     int bLastPartIsClosedOrEnded = FALSE;
    1274                 :     const char* pszLine;
    1275                 : 
    1276              45 :     OGRLineString lineString;
    1277                 : 
    1278             234 :     while((pszLine = CPLReadLine(fp)) != NULL)
    1279                 :     {
    1280             189 :         int nType = -1;
    1281             189 :         papszTokens = CSLTokenizeString(pszLine);
    1282             189 :         nTokens = CSLCount(papszTokens);
    1283                 : 
    1284             189 :         nLineNumber ++;
    1285                 : 
    1286             189 :         if (nTokens == 1 && strcmp(papszTokens[0], "99") == 0)
    1287                 :         {
    1288               0 :             if (bLastPartIsClosedOrEnded == FALSE)
    1289                 :             {
    1290                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a linear feature : %d",
    1291               0 :                         nLineNumber, nType);
    1292                 :             }
    1293               0 :             else if (multilinestring.getNumGeometries() == 0)
    1294                 :             {
    1295                 :                 CPLDebug("XPlane", "Line %d : Linear geometry is invalid or empty",
    1296               0 :                          nLineNumber);
    1297                 :             }
    1298                 :             else
    1299                 :             {
    1300               0 :                 *pbIsValid = TRUE;
    1301                 :             }
    1302               0 :             return TRUE;
    1303                 :         }
    1304             189 :         if (nTokens == 0 || assertMinCol(2) == FALSE)
    1305                 :         {
    1306               0 :             CSLDestroy(papszTokens);
    1307               0 :             continue;
    1308                 :         }
    1309                 : 
    1310             189 :         nType = atoi(papszTokens[0]);
    1311             189 :         if (nType == APT_NODE)
    1312                 :         {
    1313              20 :             RET_FALSE_IF_FAIL(assertMinCol(3));
    1314              20 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1315                 : 
    1316              20 :             if (bLastIsBezier && !bIsFirst &&
    1317                 :                 !(dfLastLat == dfLat && dfLastLon == dfLon))
    1318                 :             {
    1319                 :                 AddBezierCurve(lineString,
    1320                 :                                dfLastLat, dfLastLon,
    1321                 :                                dfLastLatBezier, dfLastLonBezier,
    1322               0 :                                dfLat, dfLon);
    1323                 :             }
    1324                 :             else
    1325              20 :                 lineString.addPoint(dfLon, dfLat);
    1326                 : 
    1327              20 :             bLastPartIsClosedOrEnded = FALSE;
    1328              20 :             bLastIsBezier = FALSE;
    1329                 :         }
    1330             169 :         else if (nType == APT_NODE_WITH_BEZIER)
    1331                 :         {
    1332              79 :             RET_FALSE_IF_FAIL(assertMinCol(5));
    1333              79 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1334              79 :             RET_FALSE_IF_FAIL(readLatLon(&dfLatBezier, &dfLonBezier, 3));
    1335                 : 
    1336              79 :             if (bLastIsBezier)
    1337                 :             {
    1338                 :                 AddBezierCurve(lineString,
    1339                 :                                dfLastLat, dfLastLon,
    1340                 :                                dfLastLatBezier, dfLastLonBezier,
    1341                 :                                dfLatBezier, dfLonBezier,
    1342              48 :                                dfLat, dfLon);
    1343                 :             }
    1344              31 :             else if (!bIsFirst && !(dfLastLat == dfLat && dfLastLon == dfLon))
    1345                 :             {
    1346               2 :                 double dfCtrLatBezier = dfLat - (dfLatBezier - dfLat);
    1347               2 :                 double dfCtrLonBezier = dfLon - (dfLonBezier - dfLon);
    1348                 :                 AddBezierCurve(lineString,
    1349                 :                                dfLastLat, dfLastLon,
    1350                 :                                dfCtrLatBezier, dfCtrLonBezier,
    1351               2 :                                dfLat, dfLon);
    1352                 :             }
    1353                 : 
    1354              79 :             bLastPartIsClosedOrEnded = FALSE;
    1355              79 :             bLastIsBezier = TRUE;
    1356              79 :             dfLastLatBezier = dfLatBezier;
    1357              79 :             dfLastLonBezier = dfLonBezier;
    1358                 :         }
    1359             103 :         else if (nType == APT_NODE_CLOSE || nType == APT_NODE_END)
    1360                 :         {
    1361              13 :             RET_FALSE_IF_FAIL(assertMinCol(3));
    1362              13 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1363              13 :             if (bIsFirst)
    1364                 :             {
    1365                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a linear feature : %d",
    1366               0 :                         nLineNumber, nType);
    1367               0 :                 return TRUE;
    1368                 :             }
    1369                 : 
    1370              13 :             if (bLastIsBezier && !(dfLastLat == dfLat && dfLastLon == dfLon))
    1371                 :             {
    1372                 :                 AddBezierCurve(lineString,
    1373                 :                                dfLastLat, dfLastLon,
    1374                 :                                dfLastLatBezier, dfLastLonBezier,
    1375               0 :                                dfLat, dfLon);
    1376                 :             }
    1377                 :             else
    1378              13 :                 lineString.addPoint(dfLon, dfLat);
    1379                 : 
    1380              13 :             if (nType == APT_NODE_CLOSE )
    1381               0 :                 lineString.closeRings();
    1382                 : 
    1383              13 :             if (lineString.getNumPoints() < 2)
    1384                 :             {
    1385                 :                 CPLDebug("XPlane", "Line %d : A linestring has less than 2 points",
    1386               0 :                          nLineNumber);
    1387                 :             }
    1388                 :             else
    1389                 :             {
    1390              13 :                 multilinestring.addGeometry(&lineString);
    1391                 :             }
    1392              13 :             lineString.empty();
    1393                 : 
    1394              13 :             bLastPartIsClosedOrEnded = TRUE;
    1395              13 :             bLastIsBezier = FALSE;
    1396                 :         }
    1397             109 :         else if (nType == APT_NODE_CLOSE_WITH_BEZIER || nType == APT_NODE_END_WITH_BEZIER)
    1398                 :         {
    1399              32 :             RET_FALSE_IF_FAIL(assertMinCol(5));
    1400              32 :             RET_FALSE_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1401              32 :             RET_FALSE_IF_FAIL(readLatLon(&dfLatBezier, &dfLonBezier, 3));
    1402              32 :             if (bIsFirst)
    1403                 :             {
    1404                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a linear feature : %d",
    1405               0 :                         nLineNumber, nType);
    1406               0 :                 return TRUE;
    1407                 :             }
    1408                 : 
    1409              32 :             if (bLastIsBezier)
    1410                 :             {
    1411                 :                 AddBezierCurve(lineString,
    1412                 :                                dfLastLat, dfLastLon,
    1413                 :                                dfLastLatBezier, dfLastLonBezier,
    1414                 :                                dfLatBezier, dfLonBezier,
    1415              31 :                                dfLat, dfLon);
    1416                 :             }
    1417               2 :             else if (!bIsFirst && !(dfLastLat == dfLat && dfLastLon == dfLon))
    1418                 :             {
    1419               1 :                 double dfCtrLatBezier = dfLat - (dfLatBezier - dfLat);
    1420               1 :                 double dfCtrLonBezier = dfLon - (dfLonBezier - dfLon);
    1421                 :                 AddBezierCurve(lineString,
    1422                 :                                dfLastLat, dfLastLon,
    1423                 :                                dfCtrLatBezier, dfCtrLonBezier,
    1424               1 :                                dfLat, dfLon);
    1425                 :             }
    1426                 :             else
    1427                 :             {
    1428               0 :                 lineString.addPoint(dfLon, dfLat);
    1429                 :             }
    1430                 : 
    1431              32 :             if (nType == APT_NODE_CLOSE_WITH_BEZIER)
    1432                 :             {
    1433               0 :                 if (bFirstIsBezier)
    1434                 :                 {
    1435                 :                     AddBezierCurve(lineString,
    1436                 :                                 dfLat, dfLon,
    1437                 :                                 dfLatBezier, dfLonBezier,
    1438                 :                                 dfFirstLatBezier, dfFirstLonBezier,
    1439               0 :                                 dfFirstLat, dfFirstLon);
    1440                 :                 }
    1441                 :                 else
    1442                 :                 {
    1443               0 :                     lineString.closeRings();
    1444                 :                 }
    1445                 :             }
    1446                 : 
    1447              32 :             if (lineString.getNumPoints() < 2)
    1448                 :             {
    1449                 :                 CPLDebug("XPlane", "Line %d : A linestring has less than 2 points",
    1450               0 :                          nLineNumber);
    1451                 :             }
    1452                 :             else
    1453                 :             {
    1454              32 :                 multilinestring.addGeometry(&lineString);
    1455                 :             }
    1456              32 :             lineString.empty();
    1457                 : 
    1458              32 :             bLastPartIsClosedOrEnded = TRUE;
    1459              32 :             bLastIsBezier = FALSE; /* we don't want to draw an arc between two parts */
    1460                 :         }
    1461                 :         else
    1462                 :         {
    1463              45 :             if (bLastPartIsClosedOrEnded == FALSE)
    1464                 :             {
    1465                 :                 CPLDebug("XPlane", "Line %d : Unexpected token when reading a linear feature : %d",
    1466               0 :                         nLineNumber, nType);
    1467                 :             }
    1468              45 :             else if (multilinestring.getNumGeometries() == 0)
    1469                 :             {
    1470                 :                 CPLDebug("XPlane", "Line %d : Linear geometry is invalid or empty",
    1471               0 :                          nLineNumber);
    1472                 :             }
    1473                 :             else
    1474                 :             {
    1475              45 :                 *pbIsValid = TRUE;
    1476                 :             }
    1477              45 :             return TRUE;
    1478                 :         }
    1479                 : 
    1480             144 :         if (bIsFirst)
    1481                 :         {
    1482              45 :             dfFirstLat = dfLat;
    1483              45 :             dfFirstLon = dfLon;
    1484              45 :             dfFirstLatBezier = dfLatBezier;
    1485              45 :             dfFirstLonBezier = dfLonBezier;
    1486              45 :             bFirstIsBezier = bLastIsBezier;
    1487                 :         }
    1488             144 :         bIsFirst = bLastPartIsClosedOrEnded;
    1489                 : 
    1490             144 :         dfLastLat = dfLat;
    1491             144 :         dfLastLon = dfLon;
    1492             144 :         bLastIsValid = TRUE;
    1493                 : 
    1494             144 :         CSLDestroy(papszTokens);
    1495                 :     }
    1496                 : 
    1497                 :     CPLAssert(0);
    1498                 : 
    1499               0 :     papszTokens = NULL;
    1500                 : 
    1501               0 :     return FALSE;
    1502                 : }
    1503                 : 
    1504                 : /************************************************************************/
    1505                 : /*                      ParseAPTLinearFeature()                         */
    1506                 : /************************************************************************/
    1507                 : 
    1508                 : /* This function will eat records until the end of the linear feature definition */
    1509                 : /* Return TRUE if the main parser must re-scan the current record */
    1510                 : 
    1511              45 : void OGRXPlaneAptReader::ParseAPTLinearFeature()
    1512                 : {
    1513              45 :     CPLString osLinearFeatureName;
    1514                 : 
    1515              45 :     RET_IF_FAIL(assertMinCol(2));
    1516                 : 
    1517              45 :     osLinearFeatureName = readStringUntilEnd(2);
    1518                 : 
    1519              45 :     CSLDestroy(papszTokens);
    1520              45 :     papszTokens = NULL;
    1521                 : 
    1522              45 :     OGRMultiLineString multilinestring;
    1523              45 :     int bIsValid = FALSE;
    1524              45 :     bResumeLine = ParseLinearGeometry(multilinestring, &bIsValid);
    1525              45 :     if (bIsValid && poAPTLinearFeatureLayer)
    1526                 :     {
    1527                 :         poAPTLinearFeatureLayer->AddFeature(osAptICAO, osLinearFeatureName,
    1528              45 :                                             &multilinestring);
    1529              45 :     }
    1530                 : }
    1531                 : 
    1532                 : /************************************************************************/
    1533                 : /*                         ParseTowerRecord()                           */
    1534                 : /************************************************************************/
    1535                 : 
    1536               4 : void OGRXPlaneAptReader::ParseTowerRecord()
    1537                 : {
    1538               4 :     RET_IF_FAIL(assertMinCol(6));
    1539                 : 
    1540               4 :     RET_IF_FAIL(readLatLon(&dfLatTower, &dfLonTower, 1));
    1541                 : 
    1542                 :     /* feet to meter */
    1543               4 :     RET_IF_FAIL(readDoubleWithBoundsAndConversion(&dfHeightTower, 3, "tower height", FEET_TO_METER, 0., 300.));
    1544                 : 
    1545                 :     // papszTokens[4] ignored
    1546                 : 
    1547               4 :     osTowerName = readStringUntilEnd(5);
    1548                 : 
    1549               4 :     bTowerFound = TRUE;
    1550                 : }
    1551                 : 
    1552                 : 
    1553                 : /************************************************************************/
    1554                 : /*                            ParseATCRecord()                          */
    1555                 : /************************************************************************/
    1556                 : 
    1557              42 : void OGRXPlaneAptReader::ParseATCRecord(int nType)
    1558                 : {
    1559                 :     double dfFrequency;
    1560              42 :     CPLString osFreqName;
    1561                 : 
    1562              42 :     RET_IF_FAIL(assertMinCol(2));
    1563                 : 
    1564              42 :     RET_IF_FAIL(readDouble(&dfFrequency, 1, "frequency"));
    1565              42 :     dfFrequency /= 100.;
    1566                 : 
    1567              42 :     osFreqName = readStringUntilEnd(2);
    1568                 : 
    1569              42 :     if (poATCFreqLayer)
    1570                 :     {
    1571                 :         poATCFreqLayer->AddFeature(osAptICAO,
    1572                 :                                     (nType == APT_ATC_AWOS_ASOS_ATIS) ? "ATIS" :
    1573                 :                                     (nType == APT_ATC_CTAF) ? "CTAF" :
    1574                 :                                     (nType == APT_ATC_CLD) ? "CLD" :
    1575                 :                                     (nType == APT_ATC_GND) ? "GND" :
    1576                 :                                     (nType == APT_ATC_TWR) ? "TWR" :
    1577                 :                                     (nType == APT_ATC_APP) ? "APP" :
    1578                 :                                     (nType == APT_ATC_DEP) ? "DEP" : "UNK",
    1579              42 :                                     osFreqName, dfFrequency);
    1580               0 :     }
    1581                 : }
    1582                 : 
    1583                 : 
    1584                 : /************************************************************************/
    1585                 : /*                      ParseStartupLocationRecord()                    */
    1586                 : /************************************************************************/
    1587                 : 
    1588             110 : void OGRXPlaneAptReader::ParseStartupLocationRecord()
    1589                 : {
    1590                 :     double dfLat, dfLon, dfTrueHeading;
    1591             110 :     CPLString osName;
    1592                 : 
    1593             110 :     RET_IF_FAIL(assertMinCol(4));
    1594                 : 
    1595             110 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1596                 : 
    1597             110 :     RET_IF_FAIL(readTrueHeading(&dfTrueHeading, 3));
    1598                 : 
    1599             110 :     osName = readStringUntilEnd(4);
    1600                 : 
    1601             110 :     if (poStartupLocationLayer)
    1602             110 :         poStartupLocationLayer->AddFeature(osAptICAO, osName, dfLat, dfLon, dfTrueHeading);
    1603                 : }
    1604                 : 
    1605                 : /************************************************************************/
    1606                 : /*                       ParseLightBeaconRecord()                       */
    1607                 : /************************************************************************/
    1608                 : 
    1609               3 : void OGRXPlaneAptReader::ParseLightBeaconRecord()
    1610                 : {
    1611                 :     double dfLat, dfLon;
    1612                 :     int eColor;
    1613               3 :     CPLString osName;
    1614                 : 
    1615               3 :     RET_IF_FAIL(assertMinCol(4));
    1616               3 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1617               3 :     eColor = atoi(papszTokens[3]);
    1618               3 :     osName = readStringUntilEnd(4);
    1619                 : 
    1620               3 :     if (poAPTLightBeaconLayer)
    1621                 :         poAPTLightBeaconLayer->AddFeature(osAptICAO, osName, dfLat, dfLon,
    1622               3 :                                             APTLightBeaconColorEnumeration.GetText(eColor));
    1623                 : }
    1624                 : 
    1625                 : /************************************************************************/
    1626                 : /*                         ParseWindsockRecord()                        */
    1627                 : /************************************************************************/
    1628                 : 
    1629              25 : void OGRXPlaneAptReader::ParseWindsockRecord()
    1630                 : {
    1631                 :     double dfLat, dfLon;
    1632                 :     int bIsIllumnited;
    1633              25 :     CPLString osName;
    1634                 : 
    1635              25 :     RET_IF_FAIL(assertMinCol(4));
    1636                 : 
    1637              25 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1638              25 :     bIsIllumnited = atoi(papszTokens[3]);
    1639              25 :     osName = readStringUntilEnd(4);
    1640                 : 
    1641              25 :     if (poAPTWindsockLayer)
    1642                 :         poAPTWindsockLayer->AddFeature(osAptICAO, osName, dfLat, dfLon,
    1643              25 :                                         bIsIllumnited);
    1644                 : }
    1645                 : 
    1646                 : /************************************************************************/
    1647                 : /*                        ParseTaxiwaySignRecord                        */
    1648                 : /************************************************************************/
    1649                 : 
    1650              17 : void OGRXPlaneAptReader::ParseTaxiwaySignRecord()
    1651                 : {
    1652                 :     double dfLat, dfLon;
    1653                 :     double dfTrueHeading;
    1654                 :     int nSize;
    1655              17 :     CPLString osText;
    1656                 : 
    1657              17 :     RET_IF_FAIL(assertMinCol(7));
    1658                 : 
    1659              17 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1660              17 :     RET_IF_FAIL(readTrueHeading(&dfTrueHeading, 3, "heading"));
    1661                 :     /* papszTokens[4] : ignored. Taxiway sign style */
    1662              17 :     nSize = atoi(papszTokens[5]);
    1663              17 :     osText = readStringUntilEnd(6);
    1664                 : 
    1665              17 :     if (poTaxiwaySignLayer)
    1666                 :         poTaxiwaySignLayer->AddFeature(osAptICAO, osText, dfLat, dfLon,
    1667              17 :                                         dfTrueHeading, nSize);
    1668                 : }
    1669                 : 
    1670                 : /************************************************************************/
    1671                 : /*                    ParseVasiPapiWigWagRecord()                       */
    1672                 : /************************************************************************/
    1673                 : 
    1674              24 : void OGRXPlaneAptReader::ParseVasiPapiWigWagRecord()
    1675                 : {
    1676                 :     double dfLat, dfLon;
    1677                 :     int eType;
    1678                 :     double dfTrueHeading, dfVisualGlidePathAngle;
    1679                 :     const char* pszRwyNum;
    1680                 : 
    1681              24 :     RET_IF_FAIL(assertMinCol(7));
    1682                 : 
    1683              24 :     RET_IF_FAIL(readLatLon(&dfLat, &dfLon, 1));
    1684              24 :     eType = atoi(papszTokens[3]);
    1685              24 :     RET_IF_FAIL(readTrueHeading(&dfTrueHeading, 4, "heading"));
    1686              24 :     RET_IF_FAIL(readDoubleWithBounds(&dfVisualGlidePathAngle, 5, "visual glidepath angle", 0, 90));
    1687              24 :     pszRwyNum = papszTokens[6];
    1688                 :     /* papszTokens[7] : ignored. Type of lighting object represented */
    1689                 : 
    1690              24 :     if (poVASI_PAPI_WIGWAG_Layer)
    1691                 :         poVASI_PAPI_WIGWAG_Layer->AddFeature(osAptICAO, pszRwyNum, VASI_PAPI_WIGWAG_Enumeration.GetText(eType),
    1692                 :                                                 dfLat, dfLon,
    1693              24 :                                                 dfTrueHeading, dfVisualGlidePathAngle);
    1694                 : }
    1695                 : 
    1696                 : /************************************************************************/
    1697                 : /*                         OGRXPlaneAPTLayer()                          */
    1698                 : /************************************************************************/
    1699                 : 
    1700                 : 
    1701               1 : OGRXPlaneAPTLayer::OGRXPlaneAPTLayer() : OGRXPlaneLayer("APT")
    1702                 : {
    1703               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    1704                 : 
    1705               1 :     OGRFieldDefn oFieldID("apt_icao", OFTString );
    1706               1 :     oFieldID.SetWidth( 4 );
    1707               1 :     poFeatureDefn->AddFieldDefn( &oFieldID );
    1708                 : 
    1709               1 :     OGRFieldDefn oFieldName("apt_name", OFTString );
    1710               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    1711                 : 
    1712               1 :     OGRFieldDefn oFieldElev("elevation_m", OFTReal );
    1713               1 :     oFieldElev.SetWidth( 8 );
    1714               1 :     oFieldElev.SetPrecision( 2 );
    1715               1 :     poFeatureDefn->AddFieldDefn( &oFieldElev );
    1716                 : 
    1717               1 :     OGRFieldDefn oFieldHasTower("has_tower", OFTInteger );
    1718               1 :     oFieldHasTower.SetWidth( 1 );
    1719               1 :     poFeatureDefn->AddFieldDefn( &oFieldHasTower );
    1720                 : 
    1721               1 :     OGRFieldDefn oFieldHeightTower("hgt_tower_m", OFTReal );
    1722               1 :     oFieldHeightTower.SetWidth( 8 );
    1723               1 :     oFieldHeightTower.SetPrecision( 2 );
    1724               1 :     poFeatureDefn->AddFieldDefn( &oFieldHeightTower );
    1725                 : 
    1726               1 :     OGRFieldDefn oFieldTowerName("tower_name", OFTString );
    1727               1 :     poFeatureDefn->AddFieldDefn( &oFieldTowerName );
    1728                 : 
    1729               1 : }
    1730                 : 
    1731                 : /************************************************************************/
    1732                 : /*                           AddFeature()                               */
    1733                 : /************************************************************************/
    1734                 : 
    1735                 : OGRFeature*
    1736               8 :      OGRXPlaneAPTLayer::AddFeature(const char* pszAptICAO,
    1737                 :                                    const char* pszAptName,
    1738                 :                                    double dfElevation,
    1739                 :                                    int bHasCoordinates,
    1740                 :                                    double dfLat,
    1741                 :                                    double dfLon,
    1742                 :                                    int bHasTower,
    1743                 :                                    double dfHeightTower,
    1744                 :                                    const char* pszTowerName)
    1745                 : {
    1746               8 :     int nCount = 0;
    1747               8 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    1748               8 :     poFeature->SetField( nCount++, pszAptICAO );
    1749               8 :     poFeature->SetField( nCount++, pszAptName );
    1750               8 :     poFeature->SetField( nCount++, dfElevation );
    1751               8 :     poFeature->SetField( nCount++, bHasTower );
    1752               8 :     if (bHasCoordinates)
    1753                 :     {
    1754               8 :         poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    1755                 :     }
    1756                 :     else
    1757                 :     {
    1758               0 :         CPLDebug("XPlane", "Airport %s/%s has no coordinates", pszAptICAO, pszAptName);
    1759                 :     }
    1760               8 :     if (bHasTower)
    1761                 :     {
    1762               4 :         poFeature->SetField( nCount++, dfHeightTower );
    1763               4 :         poFeature->SetField( nCount++, pszTowerName );
    1764                 :     }
    1765                 : 
    1766               8 :     RegisterFeature(poFeature);
    1767                 : 
    1768               8 :     return poFeature;
    1769                 : }
    1770                 : 
    1771                 : /************************************************************************/
    1772                 : /*               OGRXPlaneRunwayThresholdLayer()                        */
    1773                 : /************************************************************************/
    1774                 : 
    1775                 : 
    1776               1 : OGRXPlaneRunwayThresholdLayer::OGRXPlaneRunwayThresholdLayer() : OGRXPlaneLayer("RunwayThreshold")
    1777                 : {
    1778               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    1779                 : 
    1780               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    1781               1 :     oFieldAptICAO.SetWidth( 4 );
    1782               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    1783                 : 
    1784               1 :     OGRFieldDefn oFieldRwyNum("rwy_num", OFTString );
    1785               1 :     oFieldRwyNum.SetWidth( 3 );
    1786               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum );
    1787                 : 
    1788               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    1789               1 :     oFieldWidth.SetWidth( 3 );
    1790               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    1791                 : 
    1792               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    1793               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    1794                 : 
    1795               1 :     OGRFieldDefn oFieldShoulder("shoulder", OFTString );
    1796               1 :     poFeatureDefn->AddFieldDefn( &oFieldShoulder );
    1797                 : 
    1798               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    1799               1 :     oFieldSmoothness.SetWidth( 4 );
    1800               1 :     oFieldSmoothness.SetPrecision( 2 );
    1801               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    1802                 : 
    1803               1 :     OGRFieldDefn oFieldCenterLineLights("centerline_lights", OFTInteger );
    1804               1 :     oFieldCenterLineLights.SetWidth( 1 );
    1805               1 :     poFeatureDefn->AddFieldDefn( &oFieldCenterLineLights );
    1806                 : 
    1807               1 :     OGRFieldDefn oFieldEdgeLigthing("edge_lighting", OFTString );
    1808               1 :     poFeatureDefn->AddFieldDefn( &oFieldEdgeLigthing );
    1809                 : 
    1810               1 :     OGRFieldDefn oFieldDistanceRemainingSigns("distance_remaining_signs", OFTInteger );
    1811               1 :     oFieldDistanceRemainingSigns.SetWidth( 1 );
    1812               1 :     poFeatureDefn->AddFieldDefn( &oFieldDistanceRemainingSigns );
    1813                 : 
    1814               1 :     OGRFieldDefn oFieldDisplacedThreshold("displaced_threshold_m", OFTReal );
    1815               1 :     oFieldDisplacedThreshold.SetWidth( 3 );
    1816               1 :     poFeatureDefn->AddFieldDefn( &oFieldDisplacedThreshold );
    1817                 : 
    1818               1 :     OGRFieldDefn oFieldIsDisplaced("is_displaced", OFTInteger );
    1819               1 :     oFieldIsDisplaced.SetWidth( 1 );
    1820               1 :     poFeatureDefn->AddFieldDefn( &oFieldIsDisplaced );
    1821                 : 
    1822               1 :     OGRFieldDefn oFieldStopwayLength("stopway_length_m", OFTReal );
    1823               1 :     oFieldStopwayLength.SetWidth( 3 );
    1824               1 :     poFeatureDefn->AddFieldDefn( &oFieldStopwayLength );
    1825                 : 
    1826               1 :     OGRFieldDefn oFieldMarkings("markings", OFTString );
    1827               1 :     poFeatureDefn->AddFieldDefn( &oFieldMarkings );
    1828                 : 
    1829               1 :     OGRFieldDefn oFieldApproachLighting("approach_lighting", OFTString );
    1830               1 :     poFeatureDefn->AddFieldDefn( &oFieldApproachLighting );
    1831                 : 
    1832               1 :     OGRFieldDefn oFieldTouchdownLights("touchdown_lights", OFTInteger );
    1833               1 :     oFieldTouchdownLights.SetWidth( 1 );
    1834               1 :     poFeatureDefn->AddFieldDefn( &oFieldTouchdownLights );
    1835                 : 
    1836               1 :     OGRFieldDefn oFieldREIL("REIL", OFTString );
    1837               1 :     poFeatureDefn->AddFieldDefn( &oFieldREIL );
    1838                 : 
    1839               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    1840               1 :     oFieldLength.SetWidth( 5 );
    1841               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    1842                 : 
    1843               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    1844               1 :     oFieldTrueHeading.SetWidth( 6 );
    1845               1 :     oFieldTrueHeading.SetPrecision( 2 );
    1846               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    1847               1 : }
    1848                 : 
    1849                 : /************************************************************************/
    1850                 : /*                           AddFeature()                               */
    1851                 : /************************************************************************/
    1852                 : 
    1853                 : OGRFeature*
    1854              38 :      OGRXPlaneRunwayThresholdLayer::AddFeature  (const char* pszAptICAO,
    1855                 :                                         const char* pszRwyNum,
    1856                 :                                         double dfLat,
    1857                 :                                         double dfLon,
    1858                 :                                         double dfWidth,
    1859                 :                                         const char* pszSurfaceType,
    1860                 :                                         const char* pszShoulderType,
    1861                 :                                         double dfSmoothness,
    1862                 :                                         int bHasCenterLineLights,
    1863                 :                                         const char* pszEdgeLighting,
    1864                 :                                         int bHasDistanceRemainingSigns,
    1865                 :                                         double dfDisplacedThresholdLength,
    1866                 :                                         double dfStopwayLength,
    1867                 :                                         const char* pszMarkings,
    1868                 :                                         const char* pszApproachLightingCode,
    1869                 :                                         int bHasTouchdownLights,
    1870                 :                                         const char* pszREIL)
    1871                 : {
    1872              38 :     int nCount = 0;
    1873              38 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    1874              38 :     poFeature->SetField( nCount++, pszAptICAO );
    1875              38 :     poFeature->SetField( nCount++, pszRwyNum );
    1876              38 :     poFeature->SetField( nCount++, dfWidth );
    1877              76 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    1878              38 :     poFeature->SetField( nCount++, pszSurfaceType );
    1879              38 :     poFeature->SetField( nCount++, pszShoulderType );
    1880              38 :     poFeature->SetField( nCount++, dfSmoothness );
    1881              38 :     poFeature->SetField( nCount++, bHasCenterLineLights );
    1882              38 :     poFeature->SetField( nCount++, pszEdgeLighting );
    1883              38 :     poFeature->SetField( nCount++, bHasDistanceRemainingSigns );
    1884              38 :     poFeature->SetField( nCount++, dfDisplacedThresholdLength );
    1885              38 :     poFeature->SetField( nCount++, FALSE);
    1886              38 :     poFeature->SetField( nCount++, dfStopwayLength );
    1887              38 :     poFeature->SetField( nCount++, pszMarkings );
    1888              38 :     poFeature->SetField( nCount++, pszApproachLightingCode );
    1889              38 :     poFeature->SetField( nCount++, bHasTouchdownLights );
    1890              38 :     poFeature->SetField( nCount++, pszREIL );
    1891                 : 
    1892              38 :     RegisterFeature(poFeature);
    1893                 : 
    1894              38 :     return poFeature;
    1895                 : }
    1896                 : 
    1897              38 : void OGRXPlaneRunwayThresholdLayer::SetRunwayLengthAndHeading(OGRFeature* poFeature,
    1898                 :                                                      double dfLength,
    1899                 :                                                      double dfHeading)
    1900                 : {
    1901              38 :     int nCount = 16;
    1902              38 :     poFeature->SetField( nCount++, dfLength );
    1903              38 :     poFeature->SetField( nCount++, dfHeading );
    1904              38 : }
    1905                 : 
    1906                 : /************************************************************************/
    1907                 : /*             AddFeatureFromNonDisplacedThreshold()                    */
    1908                 : /************************************************************************/
    1909                 : 
    1910               6 : OGRFeature* OGRXPlaneRunwayThresholdLayer::
    1911                 :         AddFeatureFromNonDisplacedThreshold(OGRFeature* poNonDisplacedThresholdFeature)
    1912                 : {
    1913               6 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    1914                 : 
    1915               6 :     poFeature->SetFrom(poNonDisplacedThresholdFeature, FALSE);
    1916                 : 
    1917               6 :     double dfDisplacedThresholdLength = poFeature->GetFieldAsDouble("displaced_threshold_m");
    1918               6 :     double dfTrueHeading = poFeature->GetFieldAsDouble("true_heading_deg");
    1919               6 :     poFeature->SetField("is_displaced", TRUE);
    1920               6 :     OGRPoint* poPoint = (OGRPoint*)poFeature->GetGeometryRef();
    1921                 :     double dfLatDisplaced, dfLonDisplaced;
    1922                 :     OGRXPlane_ExtendPosition(poPoint->getY(), poPoint->getX(),
    1923                 :                              dfDisplacedThresholdLength, dfTrueHeading,
    1924               6 :                              &dfLatDisplaced, &dfLonDisplaced);
    1925               6 :     poPoint->setX(dfLonDisplaced);
    1926               6 :     poPoint->setY(dfLatDisplaced);
    1927                 : 
    1928               6 :     RegisterFeature(poFeature);
    1929                 : 
    1930               6 :     return poFeature;
    1931                 : }
    1932                 : 
    1933                 : /************************************************************************/
    1934                 : /*                       OGRXPlaneRunwayLayer()                         */
    1935                 : /************************************************************************/
    1936                 : 
    1937                 : 
    1938                 : 
    1939               1 : OGRXPlaneRunwayLayer::OGRXPlaneRunwayLayer() : OGRXPlaneLayer("RunwayPolygon")
    1940                 : {
    1941               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    1942                 : 
    1943               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    1944               1 :     oFieldAptICAO.SetWidth( 4 );
    1945               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    1946                 : 
    1947               1 :     OGRFieldDefn oFieldRwyNum1("rwy_num1", OFTString );
    1948               1 :     oFieldRwyNum1.SetWidth( 3 );
    1949               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum1 );
    1950                 : 
    1951               1 :     OGRFieldDefn oFieldRwyNum2("rwy_num2", OFTString );
    1952               1 :     oFieldRwyNum2.SetWidth( 3 );
    1953               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum2 );
    1954                 : 
    1955               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    1956               1 :     oFieldWidth.SetWidth( 3 );
    1957               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    1958                 : 
    1959               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    1960               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    1961                 : 
    1962               1 :     OGRFieldDefn oFieldShoulder("shoulder", OFTString );
    1963               1 :     poFeatureDefn->AddFieldDefn( &oFieldShoulder );
    1964                 : 
    1965               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    1966               1 :     oFieldSmoothness.SetWidth( 4 );
    1967               1 :     oFieldSmoothness.SetPrecision( 2 );
    1968               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    1969                 : 
    1970               1 :     OGRFieldDefn oFieldCenterLineLights("centerline_lights", OFTInteger );
    1971               1 :     oFieldCenterLineLights.SetWidth( 1 );
    1972               1 :     poFeatureDefn->AddFieldDefn( &oFieldCenterLineLights );
    1973                 : 
    1974               1 :     OGRFieldDefn oFieldEdgeLigthing("edge_lighting", OFTString );
    1975               1 :     poFeatureDefn->AddFieldDefn( &oFieldEdgeLigthing );
    1976                 : 
    1977               1 :     OGRFieldDefn oFieldDistanceRemainingSigns("distance_remaining_signs", OFTInteger );
    1978               1 :     oFieldDistanceRemainingSigns.SetWidth( 1 );
    1979               1 :     poFeatureDefn->AddFieldDefn( &oFieldDistanceRemainingSigns );
    1980                 : 
    1981               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    1982               1 :     oFieldLength.SetWidth( 5 );
    1983               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    1984                 : 
    1985               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    1986               1 :     oFieldTrueHeading.SetWidth( 6 );
    1987               1 :     oFieldTrueHeading.SetPrecision( 2 );
    1988               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    1989               1 : }
    1990                 : 
    1991                 : /************************************************************************/
    1992                 : /*                           AddFeature()                               */
    1993                 : /************************************************************************/
    1994                 : 
    1995                 : 
    1996                 : OGRFeature*
    1997              19 :      OGRXPlaneRunwayLayer::AddFeature  (const char* pszAptICAO,
    1998                 :                                         const char* pszRwyNum1,
    1999                 :                                         const char* pszRwyNum2,
    2000                 :                                         double dfLat1,
    2001                 :                                         double dfLon1,
    2002                 :                                         double dfLat2,
    2003                 :                                         double dfLon2,
    2004                 :                                         double dfWidth,
    2005                 :                                         const char* pszSurfaceType,
    2006                 :                                         const char* pszShoulderType,
    2007                 :                                         double dfSmoothness,
    2008                 :                                         int bHasCenterLineLights,
    2009                 :                                         const char* pszEdgeLighting,
    2010                 :                                         int bHasDistanceRemainingSigns)
    2011                 : {
    2012              19 :     int nCount = 0;
    2013              19 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2014                 : 
    2015              19 :     double dfLength = OGRXPlane_Distance(dfLat1, dfLon1, dfLat2, dfLon2);
    2016              19 :     double dfTrack12 = OGRXPlane_Track(dfLat1, dfLon1, dfLat2, dfLon2);
    2017              19 :     double dfTrack21 = OGRXPlane_Track(dfLat2, dfLon2, dfLat1, dfLon1);
    2018                 :     double adfLat[4], adfLon[4];
    2019                 :     
    2020              19 :     OGRXPlane_ExtendPosition(dfLat1, dfLon1, dfWidth / 2, dfTrack12 - 90, &adfLat[0], &adfLon[0]);
    2021              19 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfTrack21 + 90, &adfLat[1], &adfLon[1]);
    2022              19 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfTrack21 - 90, &adfLat[2], &adfLon[2]);
    2023              19 :     OGRXPlane_ExtendPosition(dfLat1, dfLon1, dfWidth / 2, dfTrack12 + 90, &adfLat[3], &adfLon[3]);
    2024                 :     
    2025              38 :     OGRLinearRing* linearRing = new OGRLinearRing();
    2026              19 :     linearRing->setNumPoints(5);
    2027                 :     int i;
    2028              95 :     for(i=0;i<4;i++)
    2029              76 :         linearRing->setPoint(i, adfLon[i], adfLat[i]);
    2030              19 :     linearRing->setPoint(4, adfLon[0], adfLat[0]);
    2031              19 :     OGRPolygon* polygon = new OGRPolygon();
    2032              19 :      polygon->addRingDirectly( linearRing );
    2033              19 :     poFeature->SetGeometryDirectly( polygon );
    2034                 : 
    2035              19 :     poFeature->SetField( nCount++, pszAptICAO );
    2036              19 :     poFeature->SetField( nCount++, pszRwyNum1 );
    2037              19 :     poFeature->SetField( nCount++, pszRwyNum2 );
    2038              19 :     poFeature->SetField( nCount++, dfWidth );
    2039              19 :     poFeature->SetField( nCount++, pszSurfaceType );
    2040              19 :     poFeature->SetField( nCount++, pszShoulderType );
    2041              19 :     poFeature->SetField( nCount++, dfSmoothness );
    2042              19 :     poFeature->SetField( nCount++, bHasCenterLineLights );
    2043              19 :     poFeature->SetField( nCount++, pszEdgeLighting );
    2044              19 :     poFeature->SetField( nCount++, bHasDistanceRemainingSigns );
    2045              19 :     poFeature->SetField( nCount++, dfLength );
    2046              19 :     poFeature->SetField( nCount++, dfTrack12 );
    2047                 : 
    2048              19 :     RegisterFeature(poFeature);
    2049                 : 
    2050              19 :     return poFeature;
    2051                 : }
    2052                 : 
    2053                 : 
    2054                 : /************************************************************************/
    2055                 : /*                      OGRXPlaneStopwayLayer()                         */
    2056                 : /************************************************************************/
    2057                 : 
    2058                 : 
    2059                 : 
    2060               1 : OGRXPlaneStopwayLayer::OGRXPlaneStopwayLayer() : OGRXPlaneLayer("Stopway")
    2061                 : {
    2062               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2063                 : 
    2064               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2065               1 :     oFieldAptICAO.SetWidth( 4 );
    2066               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2067                 : 
    2068               1 :     OGRFieldDefn oFieldRwyNum1("rwy_num", OFTString );
    2069               1 :     oFieldRwyNum1.SetWidth( 3 );
    2070               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum1 );
    2071                 : 
    2072               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2073               1 :     oFieldWidth.SetWidth( 3 );
    2074               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2075                 : 
    2076               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2077               1 :     oFieldLength.SetWidth( 5 );
    2078               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2079               1 : }
    2080                 : 
    2081                 : /************************************************************************/
    2082                 : /*                           AddFeature()                               */
    2083                 : /************************************************************************/
    2084                 : 
    2085                 : 
    2086                 : OGRFeature*
    2087               6 :      OGRXPlaneStopwayLayer::AddFeature(const char* pszAptICAO,
    2088                 :                                        const char* pszRwyNum,
    2089                 :                                        double dfLatThreshold,
    2090                 :                                        double dfLonThreshold,
    2091                 :                                        double dfRunwayHeading,
    2092                 :                                        double dfWidth,
    2093                 :                                        double dfStopwayLength)
    2094                 : {
    2095               6 :     int nCount = 0;
    2096               6 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2097                 : 
    2098                 :     double dfLat2, dfLon2;
    2099                 :     double adfLat[4], adfLon[4];
    2100                 :     
    2101               6 :     OGRXPlane_ExtendPosition(dfLatThreshold, dfLonThreshold, dfStopwayLength, 180 + dfRunwayHeading, &dfLat2, &dfLon2);
    2102                 :     
    2103               6 :     OGRXPlane_ExtendPosition(dfLatThreshold, dfLonThreshold, dfWidth / 2, dfRunwayHeading - 90, &adfLat[0], &adfLon[0]);
    2104               6 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfRunwayHeading - 90, &adfLat[1], &adfLon[1]);
    2105               6 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfRunwayHeading + 90, &adfLat[2], &adfLon[2]);
    2106               6 :     OGRXPlane_ExtendPosition(dfLatThreshold, dfLonThreshold, dfWidth / 2, dfRunwayHeading + 90, &adfLat[3], &adfLon[3]);
    2107                 :     
    2108              12 :     OGRLinearRing* linearRing = new OGRLinearRing();
    2109               6 :     linearRing->setNumPoints(5);
    2110                 :     int i;
    2111              30 :     for(i=0;i<4;i++)
    2112              24 :         linearRing->setPoint(i, adfLon[i], adfLat[i]);
    2113               6 :     linearRing->setPoint(4, adfLon[0], adfLat[0]);
    2114               6 :     OGRPolygon* polygon = new OGRPolygon();
    2115               6 :      polygon->addRingDirectly( linearRing );
    2116               6 :     poFeature->SetGeometryDirectly( polygon );
    2117                 : 
    2118               6 :     poFeature->SetField( nCount++, pszAptICAO );
    2119               6 :     poFeature->SetField( nCount++, pszRwyNum );
    2120               6 :     poFeature->SetField( nCount++, dfWidth );
    2121               6 :     poFeature->SetField( nCount++, dfStopwayLength );
    2122                 : 
    2123               6 :     RegisterFeature(poFeature);
    2124                 : 
    2125               6 :     return poFeature;
    2126                 : }
    2127                 : 
    2128                 : /************************************************************************/
    2129                 : /*               OGRXPlaneWaterRunwayThresholdLayer()                   */
    2130                 : /************************************************************************/
    2131                 : 
    2132                 : 
    2133               1 : OGRXPlaneWaterRunwayThresholdLayer::OGRXPlaneWaterRunwayThresholdLayer() : OGRXPlaneLayer("WaterRunwayThreshold")
    2134                 : {
    2135               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2136                 : 
    2137               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2138               1 :     oFieldAptICAO.SetWidth( 4 );
    2139               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2140                 : 
    2141               1 :     OGRFieldDefn oFieldRwyNum("rwy_num", OFTString );
    2142               1 :     oFieldRwyNum.SetWidth( 3 );
    2143               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum );
    2144                 : 
    2145               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2146               1 :     oFieldWidth.SetWidth( 3 );
    2147               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2148                 : 
    2149               1 :     OGRFieldDefn oFieldHasBuoys("has_buoys", OFTInteger );
    2150               1 :     oFieldHasBuoys.SetWidth( 1 );
    2151               1 :     poFeatureDefn->AddFieldDefn( &oFieldHasBuoys );
    2152                 : 
    2153               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2154               1 :     oFieldLength.SetWidth( 5 );
    2155               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2156                 : 
    2157               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2158               1 :     oFieldTrueHeading.SetWidth( 6 );
    2159               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2160               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2161               1 : }
    2162                 : 
    2163                 : /************************************************************************/
    2164                 : /*                           AddFeature()                               */
    2165                 : /************************************************************************/
    2166                 : 
    2167                 : OGRFeature*
    2168               2 :      OGRXPlaneWaterRunwayThresholdLayer::AddFeature  (const char* pszAptICAO,
    2169                 :                                                       const char* pszRwyNum,
    2170                 :                                                       double dfLat,
    2171                 :                                                       double dfLon,
    2172                 :                                                       double dfWidth,
    2173                 :                                                       int bBuoys)
    2174                 : {
    2175               2 :     int nCount = 0;
    2176               2 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2177               2 :     poFeature->SetField( nCount++, pszAptICAO );
    2178               2 :     poFeature->SetField( nCount++, pszRwyNum );
    2179               2 :     poFeature->SetField( nCount++, dfWidth );
    2180               4 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2181               2 :     poFeature->SetField( nCount++, bBuoys );
    2182                 : 
    2183               2 :     RegisterFeature(poFeature);
    2184                 : 
    2185               2 :     return poFeature;
    2186                 : }
    2187                 : 
    2188               2 : void OGRXPlaneWaterRunwayThresholdLayer::SetRunwayLengthAndHeading(OGRFeature* poFeature,
    2189                 :                                                      double dfLength,
    2190                 :                                                      double dfHeading)
    2191                 : {
    2192               2 :     int nCount = 4;
    2193               2 :     poFeature->SetField( nCount++, dfLength );
    2194               2 :     poFeature->SetField( nCount++, dfHeading );
    2195               2 : }
    2196                 : 
    2197                 : 
    2198                 : /************************************************************************/
    2199                 : /*                      OGRXPlaneWaterRunwayLayer()                     */
    2200                 : /************************************************************************/
    2201                 : 
    2202                 : 
    2203                 : 
    2204               1 : OGRXPlaneWaterRunwayLayer::OGRXPlaneWaterRunwayLayer() : OGRXPlaneLayer("WaterRunwayPolygon")
    2205                 : {
    2206               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2207                 : 
    2208               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2209               1 :     oFieldAptICAO.SetWidth( 4 );
    2210               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2211                 : 
    2212               1 :     OGRFieldDefn oFieldRwyNum1("rwy_num1", OFTString );
    2213               1 :     oFieldRwyNum1.SetWidth( 3 );
    2214               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum1 );
    2215                 : 
    2216               1 :     OGRFieldDefn oFieldRwyNum2("rwy_num2", OFTString );
    2217               1 :     oFieldRwyNum2.SetWidth( 3 );
    2218               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum2 );
    2219                 : 
    2220               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2221               1 :     oFieldWidth.SetWidth( 3 );
    2222               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2223                 : 
    2224               1 :     OGRFieldDefn oFieldHasBuoys("has_buoys", OFTInteger );
    2225               1 :     oFieldHasBuoys.SetWidth( 1 );
    2226               1 :     poFeatureDefn->AddFieldDefn( &oFieldHasBuoys );
    2227                 : 
    2228               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2229               1 :     oFieldLength.SetWidth( 5 );
    2230               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2231                 : 
    2232               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2233               1 :     oFieldTrueHeading.SetWidth( 6 );
    2234               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2235               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2236               1 : }
    2237                 : 
    2238                 : /************************************************************************/
    2239                 : /*                           AddFeature()                               */
    2240                 : /************************************************************************/
    2241                 : 
    2242                 : OGRFeature*
    2243               1 :      OGRXPlaneWaterRunwayLayer::AddFeature  (const char* pszAptICAO,
    2244                 :                                              const char* pszRwyNum1,
    2245                 :                                              const char* pszRwyNum2,
    2246                 :                                              double dfLat1,
    2247                 :                                              double dfLon1,
    2248                 :                                              double dfLat2,
    2249                 :                                              double dfLon2,
    2250                 :                                              double dfWidth,
    2251                 :                                              int bBuoys)
    2252                 : {
    2253               1 :     int nCount = 0;
    2254               1 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2255                 : 
    2256               1 :     double dfLength = OGRXPlane_Distance(dfLat1, dfLon1, dfLat2, dfLon2);
    2257               1 :     double dfTrack12 = OGRXPlane_Track(dfLat1, dfLon1, dfLat2, dfLon2);
    2258               1 :     double dfTrack21 = OGRXPlane_Track(dfLat2, dfLon2, dfLat1, dfLon1);
    2259                 :     double adfLat[4], adfLon[4];
    2260                 :     
    2261               1 :     OGRXPlane_ExtendPosition(dfLat1, dfLon1, dfWidth / 2, dfTrack12 - 90, &adfLat[0], &adfLon[0]);
    2262               1 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfTrack21 + 90, &adfLat[1], &adfLon[1]);
    2263               1 :     OGRXPlane_ExtendPosition(dfLat2, dfLon2, dfWidth / 2, dfTrack21 - 90, &adfLat[2], &adfLon[2]);
    2264               1 :     OGRXPlane_ExtendPosition(dfLat1, dfLon1, dfWidth / 2, dfTrack12 + 90, &adfLat[3], &adfLon[3]);
    2265                 :     
    2266               2 :     OGRLinearRing* linearRing = new OGRLinearRing();
    2267               1 :     linearRing->setNumPoints(5);
    2268                 :     int i;
    2269               5 :     for(i=0;i<4;i++)
    2270               4 :         linearRing->setPoint(i, adfLon[i], adfLat[i]);
    2271               1 :     linearRing->setPoint(4, adfLon[0], adfLat[0]);
    2272               1 :     OGRPolygon* polygon = new OGRPolygon();
    2273               1 :      polygon->addRingDirectly( linearRing );
    2274               1 :     poFeature->SetGeometryDirectly( polygon );
    2275                 : 
    2276               1 :     poFeature->SetField( nCount++, pszAptICAO );
    2277               1 :     poFeature->SetField( nCount++, pszRwyNum1 );
    2278               1 :     poFeature->SetField( nCount++, pszRwyNum2 );
    2279               1 :     poFeature->SetField( nCount++, dfWidth );
    2280               1 :     poFeature->SetField( nCount++, bBuoys );
    2281               1 :     poFeature->SetField( nCount++, dfLength );
    2282               1 :     poFeature->SetField( nCount++, dfTrack12 );
    2283                 : 
    2284               1 :     RegisterFeature(poFeature);
    2285                 : 
    2286               1 :     return poFeature;
    2287                 : }
    2288                 : 
    2289                 : 
    2290                 : /************************************************************************/
    2291                 : /*                     OGRXPlaneHelipadLayer()                          */
    2292                 : /************************************************************************/
    2293                 : 
    2294                 : 
    2295               1 : OGRXPlaneHelipadLayer::OGRXPlaneHelipadLayer() : OGRXPlaneLayer("Helipad")
    2296                 : {
    2297               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2298                 : 
    2299               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2300               1 :     oFieldAptICAO.SetWidth( 4 );
    2301               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2302                 : 
    2303               1 :     OGRFieldDefn oFieldHelipadName("helipad_name", OFTString );
    2304               1 :     oFieldHelipadName.SetWidth( 5 );
    2305               1 :     poFeatureDefn->AddFieldDefn( &oFieldHelipadName );
    2306                 : 
    2307               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2308               1 :     oFieldTrueHeading.SetWidth( 6 );
    2309               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2310               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2311                 : 
    2312               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2313               1 :     oFieldLength.SetWidth( 5 );
    2314               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2315                 : 
    2316               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2317               1 :     oFieldWidth.SetWidth( 3 );
    2318               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2319                 : 
    2320               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    2321               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    2322                 : 
    2323               1 :     OGRFieldDefn oFieldMarkings("markings", OFTString );
    2324               1 :     poFeatureDefn->AddFieldDefn( &oFieldMarkings );
    2325                 : 
    2326               1 :     OGRFieldDefn oFieldShoulder("shoulder", OFTString );
    2327               1 :     poFeatureDefn->AddFieldDefn( &oFieldShoulder );
    2328                 : 
    2329               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    2330               1 :     oFieldSmoothness.SetWidth( 4 );
    2331               1 :     oFieldSmoothness.SetPrecision( 2 );
    2332               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    2333                 : 
    2334               1 :     OGRFieldDefn oFieldEdgeLighting("edge_lighting", OFTString );
    2335               1 :     poFeatureDefn->AddFieldDefn( &oFieldEdgeLighting );
    2336                 : 
    2337               1 : }
    2338                 : 
    2339                 : /************************************************************************/
    2340                 : /*                           AddFeature()                               */
    2341                 : /************************************************************************/
    2342                 : 
    2343                 : OGRFeature*
    2344               2 :      OGRXPlaneHelipadLayer::AddFeature (const char* pszAptICAO,
    2345                 :                                         const char* pszHelipadNum,
    2346                 :                                         double dfLat,
    2347                 :                                         double dfLon,
    2348                 :                                         double dfTrueHeading,
    2349                 :                                         double dfLength,
    2350                 :                                         double dfWidth,
    2351                 :                                         const char* pszSurfaceType,
    2352                 :                                         const char* pszMarkings,
    2353                 :                                         const char* pszShoulderType,
    2354                 :                                         double dfSmoothness,
    2355                 :                                         const char* pszEdgeLighting)
    2356                 : {
    2357               2 :     int nCount = 0;
    2358               2 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2359               2 :     poFeature->SetField( nCount++, pszAptICAO );
    2360               2 :     poFeature->SetField( nCount++, pszHelipadNum );
    2361               4 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2362               2 :     poFeature->SetField( nCount++, dfTrueHeading );
    2363               2 :     poFeature->SetField( nCount++, dfLength );
    2364               2 :     poFeature->SetField( nCount++, dfWidth );
    2365               2 :     poFeature->SetField( nCount++, pszSurfaceType );
    2366               2 :     poFeature->SetField( nCount++, pszMarkings );
    2367               2 :     poFeature->SetField( nCount++, pszShoulderType );
    2368               2 :     poFeature->SetField( nCount++, dfSmoothness );
    2369               2 :     poFeature->SetField( nCount++, pszEdgeLighting );
    2370                 : 
    2371               2 :     RegisterFeature(poFeature);
    2372                 : 
    2373               2 :     return poFeature;
    2374                 : }
    2375                 : 
    2376                 : /************************************************************************/
    2377                 : /*                 OGRXPlaneHelipadPolygonLayer()                       */
    2378                 : /************************************************************************/
    2379                 : 
    2380                 : 
    2381               1 : OGRXPlaneHelipadPolygonLayer::OGRXPlaneHelipadPolygonLayer() : OGRXPlaneLayer("HelipadPolygon")
    2382                 : {
    2383               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2384                 : 
    2385               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2386               1 :     oFieldAptICAO.SetWidth( 4 );
    2387               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2388                 : 
    2389               1 :     OGRFieldDefn oFieldHelipadName("helipad_name", OFTString );
    2390               1 :     oFieldHelipadName.SetWidth( 5 );
    2391               1 :     poFeatureDefn->AddFieldDefn( &oFieldHelipadName );
    2392                 : 
    2393               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2394               1 :     oFieldTrueHeading.SetWidth( 6 );
    2395               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2396               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2397                 : 
    2398               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2399               1 :     oFieldLength.SetWidth( 5 );
    2400               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2401                 : 
    2402               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2403               1 :     oFieldWidth.SetWidth( 3 );
    2404               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2405                 : 
    2406               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    2407               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    2408                 : 
    2409               1 :     OGRFieldDefn oFieldMarkings("markings", OFTString );
    2410               1 :     poFeatureDefn->AddFieldDefn( &oFieldMarkings );
    2411                 : 
    2412               1 :     OGRFieldDefn oFieldShoulder("shoulder", OFTString );
    2413               1 :     poFeatureDefn->AddFieldDefn( &oFieldShoulder );
    2414                 : 
    2415               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    2416               1 :     oFieldSmoothness.SetWidth( 4 );
    2417               1 :     oFieldSmoothness.SetPrecision( 2 );
    2418               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    2419                 : 
    2420               1 :     OGRFieldDefn oFieldEdgeLighting("edge_lighting", OFTString );
    2421               1 :     poFeatureDefn->AddFieldDefn( &oFieldEdgeLighting );
    2422                 : 
    2423               1 : }
    2424                 : 
    2425                 : /************************************************************************/
    2426                 : /*                           AddFeature()                               */
    2427                 : /************************************************************************/
    2428                 : 
    2429                 : OGRFeature*
    2430               2 :      OGRXPlaneHelipadPolygonLayer::AddFeature (const char* pszAptICAO,
    2431                 :                                                const char* pszHelipadNum,
    2432                 :                                                double dfLat,
    2433                 :                                                double dfLon,
    2434                 :                                                double dfTrueHeading,
    2435                 :                                                double dfLength,
    2436                 :                                                double dfWidth,
    2437                 :                                                const char* pszSurfaceType,
    2438                 :                                                const char* pszMarkings,
    2439                 :                                                const char* pszShoulderType,
    2440                 :                                                double dfSmoothness,
    2441                 :                                                const char* pszEdgeLighting)
    2442                 : {
    2443               2 :     int nCount = 0;
    2444               2 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2445                 : 
    2446                 :     double dfBeforeLat, dfBeforeLon;
    2447                 :     double dfAfterLat, dfAfterLon;
    2448                 :     double adfLat[4], adfLon[4];
    2449                 : 
    2450               2 :     OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading + 180, &dfBeforeLat, &dfBeforeLon);
    2451               2 :     OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading, &dfAfterLat, &dfAfterLon);
    2452                 : 
    2453               2 :     OGRXPlane_ExtendPosition(dfBeforeLat, dfBeforeLon, dfWidth / 2, dfTrueHeading - 90, &adfLat[0], &adfLon[0]);
    2454               2 :     OGRXPlane_ExtendPosition(dfAfterLat, dfAfterLon, dfWidth / 2, dfTrueHeading - 90, &adfLat[1], &adfLon[1]);
    2455               2 :     OGRXPlane_ExtendPosition(dfAfterLat, dfAfterLon, dfWidth / 2, dfTrueHeading + 90, &adfLat[2], &adfLon[2]);
    2456               2 :     OGRXPlane_ExtendPosition(dfBeforeLat, dfBeforeLon, dfWidth / 2, dfTrueHeading + 90, &adfLat[3], &adfLon[3]);
    2457                 : 
    2458               4 :     OGRLinearRing* linearRing = new OGRLinearRing();
    2459               2 :     linearRing->setNumPoints(5);
    2460                 :     int i;
    2461              10 :     for(i=0;i<4;i++)
    2462               8 :         linearRing->setPoint(i, adfLon[i], adfLat[i]);
    2463               2 :     linearRing->setPoint(4, adfLon[0], adfLat[0]);
    2464               2 :     OGRPolygon* polygon = new OGRPolygon();
    2465               2 :      polygon->addRingDirectly( linearRing );
    2466               2 :     poFeature->SetGeometryDirectly( polygon );
    2467                 : 
    2468               2 :     poFeature->SetField( nCount++, pszAptICAO );
    2469               2 :     poFeature->SetField( nCount++, pszHelipadNum );
    2470               2 :     poFeature->SetField( nCount++, dfTrueHeading );
    2471               2 :     poFeature->SetField( nCount++, dfLength );
    2472               2 :     poFeature->SetField( nCount++, dfWidth );
    2473               2 :     poFeature->SetField( nCount++, pszSurfaceType );
    2474               2 :     poFeature->SetField( nCount++, pszMarkings );
    2475               2 :     poFeature->SetField( nCount++, pszShoulderType );
    2476               2 :     poFeature->SetField( nCount++, dfSmoothness );
    2477               2 :     poFeature->SetField( nCount++, pszEdgeLighting );
    2478                 : 
    2479               2 :     RegisterFeature(poFeature);
    2480                 : 
    2481               2 :     return poFeature;
    2482                 : }
    2483                 : 
    2484                 : 
    2485                 : /************************************************************************/
    2486                 : /*                 OGRXPlaneTaxiwayRectangleLayer()                     */
    2487                 : /************************************************************************/
    2488                 : 
    2489                 : 
    2490               1 : OGRXPlaneTaxiwayRectangleLayer::OGRXPlaneTaxiwayRectangleLayer() : OGRXPlaneLayer("TaxiwayRectangle")
    2491                 : {
    2492               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2493                 : 
    2494               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2495               1 :     oFieldAptICAO.SetWidth( 4 );
    2496               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2497                 : 
    2498               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2499               1 :     oFieldTrueHeading.SetWidth( 6 );
    2500               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2501               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2502                 : 
    2503               1 :     OGRFieldDefn oFieldLength("length_m", OFTReal );
    2504               1 :     oFieldLength.SetWidth( 5 );
    2505               1 :     poFeatureDefn->AddFieldDefn( &oFieldLength );
    2506                 : 
    2507               1 :     OGRFieldDefn oFieldWidth("width_m", OFTReal );
    2508               1 :     oFieldWidth.SetWidth( 3 );
    2509               1 :     poFeatureDefn->AddFieldDefn( &oFieldWidth );
    2510                 : 
    2511               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    2512               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    2513                 : 
    2514               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    2515               1 :     oFieldSmoothness.SetWidth( 4 );
    2516               1 :     oFieldSmoothness.SetPrecision( 2 );
    2517               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    2518                 : 
    2519               1 :     OGRFieldDefn oFieldBlueEdgeLighting("edge_lighting", OFTInteger );
    2520               1 :     oFieldBlueEdgeLighting.SetWidth( 1 );
    2521               1 :     poFeatureDefn->AddFieldDefn( &oFieldBlueEdgeLighting );
    2522                 : 
    2523               1 : }
    2524                 : 
    2525                 : /************************************************************************/
    2526                 : /*                           AddFeature()                               */
    2527                 : /************************************************************************/
    2528                 : 
    2529                 : OGRFeature*
    2530             437 :      OGRXPlaneTaxiwayRectangleLayer::AddFeature(const char* pszAptICAO,
    2531                 :                                                 double dfLat,
    2532                 :                                                 double dfLon,
    2533                 :                                                 double dfTrueHeading,
    2534                 :                                                 double dfLength,
    2535                 :                                                 double dfWidth,
    2536                 :                                                 const char* pszSurfaceType,
    2537                 :                                                 double dfSmoothness,
    2538                 :                                                 int bBlueEdgeLights)
    2539                 : {
    2540             437 :     int nCount = 0;
    2541             437 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2542                 : 
    2543                 :     double dfBeforeLat, dfBeforeLon;
    2544                 :     double dfAfterLat, dfAfterLon;
    2545                 :     double adfLat[4], adfLon[4];
    2546                 : 
    2547             437 :     OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading + 180, &dfBeforeLat, &dfBeforeLon);
    2548             437 :     OGRXPlane_ExtendPosition(dfLat, dfLon, dfLength / 2, dfTrueHeading, &dfAfterLat, &dfAfterLon);
    2549                 : 
    2550             437 :     OGRXPlane_ExtendPosition(dfBeforeLat, dfBeforeLon, dfWidth / 2, dfTrueHeading - 90, &adfLat[0], &adfLon[0]);
    2551             437 :     OGRXPlane_ExtendPosition(dfAfterLat, dfAfterLon, dfWidth / 2, dfTrueHeading - 90, &adfLat[1], &adfLon[1]);
    2552             437 :     OGRXPlane_ExtendPosition(dfAfterLat, dfAfterLon, dfWidth / 2, dfTrueHeading + 90, &adfLat[2], &adfLon[2]);
    2553             437 :     OGRXPlane_ExtendPosition(dfBeforeLat, dfBeforeLon, dfWidth / 2, dfTrueHeading + 90, &adfLat[3], &adfLon[3]);
    2554                 : 
    2555             874 :     OGRLinearRing* linearRing = new OGRLinearRing();
    2556             437 :     linearRing->setNumPoints(5);
    2557                 :     int i;
    2558            2185 :     for(i=0;i<4;i++)
    2559            1748 :         linearRing->setPoint(i, adfLon[i], adfLat[i]);
    2560             437 :     linearRing->setPoint(4, adfLon[0], adfLat[0]);
    2561             437 :     OGRPolygon* polygon = new OGRPolygon();
    2562             437 :      polygon->addRingDirectly( linearRing );
    2563             437 :     poFeature->SetGeometryDirectly( polygon );
    2564                 : 
    2565             437 :     poFeature->SetField( nCount++, pszAptICAO );
    2566             437 :     poFeature->SetField( nCount++, dfTrueHeading );
    2567             437 :     poFeature->SetField( nCount++, dfLength );
    2568             437 :     poFeature->SetField( nCount++, dfWidth );
    2569             437 :     poFeature->SetField( nCount++, pszSurfaceType );
    2570             437 :     poFeature->SetField( nCount++, dfSmoothness );
    2571             437 :     poFeature->SetField( nCount++, bBlueEdgeLights );
    2572                 : 
    2573             437 :     RegisterFeature(poFeature);
    2574                 : 
    2575             437 :     return poFeature;
    2576                 : }
    2577                 : 
    2578                 : 
    2579                 : /************************************************************************/
    2580                 : /*                      OGRXPlanePavementLayer()                        */
    2581                 : /************************************************************************/
    2582                 : 
    2583                 : 
    2584               1 : OGRXPlanePavementLayer::OGRXPlanePavementLayer() : OGRXPlaneLayer("Pavement")
    2585                 : {
    2586               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2587                 : 
    2588               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2589               1 :     oFieldAptICAO.SetWidth( 4 );
    2590               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2591                 : 
    2592               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2593               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2594                 : 
    2595               1 :     OGRFieldDefn oFieldSurface("surface", OFTString );
    2596               1 :     poFeatureDefn->AddFieldDefn( &oFieldSurface );
    2597                 : 
    2598               1 :     OGRFieldDefn oFieldSmoothness("smoothness", OFTReal );
    2599               1 :     oFieldSmoothness.SetWidth( 4 );
    2600               1 :     oFieldSmoothness.SetPrecision( 2 );
    2601               1 :     poFeatureDefn->AddFieldDefn( &oFieldSmoothness );
    2602                 : 
    2603               1 :     OGRFieldDefn oFieldTextureHeading("texture_heading", OFTReal );
    2604               1 :     oFieldTextureHeading.SetWidth( 6 );
    2605               1 :     oFieldTextureHeading.SetPrecision( 2 );
    2606               1 :     poFeatureDefn->AddFieldDefn( &oFieldTextureHeading );
    2607                 : 
    2608               1 : }
    2609                 : 
    2610                 : /************************************************************************/
    2611                 : /*                           AddFeature()                               */
    2612                 : /************************************************************************/
    2613                 : 
    2614                 : OGRFeature*
    2615              11 :      OGRXPlanePavementLayer::AddFeature(const char* pszAptICAO,
    2616                 :                                         const char* pszPavementName,
    2617                 :                                         const char* pszSurfaceType,
    2618                 :                                         double dfSmoothness,
    2619                 :                                         double dfTextureHeading,
    2620                 :                                         OGRPolygon* poPolygon)
    2621                 : {
    2622              11 :     int nCount = 0;
    2623              11 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2624                 : 
    2625              11 :     poFeature->SetGeometry( poPolygon );
    2626                 : 
    2627              11 :     poFeature->SetField( nCount++, pszAptICAO );
    2628              11 :     poFeature->SetField( nCount++, pszPavementName );
    2629              11 :     poFeature->SetField( nCount++, pszSurfaceType );
    2630              11 :     poFeature->SetField( nCount++, dfSmoothness );
    2631              11 :     poFeature->SetField( nCount++, dfTextureHeading );
    2632                 : 
    2633              11 :     RegisterFeature(poFeature);
    2634                 : 
    2635              11 :     return poFeature;
    2636                 : }
    2637                 : 
    2638                 : 
    2639                 : 
    2640                 : /************************************************************************/
    2641                 : /*                   OGRXPlaneAPTBoundaryLayer()                        */
    2642                 : /************************************************************************/
    2643                 : 
    2644                 : 
    2645               1 : OGRXPlaneAPTBoundaryLayer::OGRXPlaneAPTBoundaryLayer() : OGRXPlaneLayer("APTBoundary")
    2646                 : {
    2647               1 :     poFeatureDefn->SetGeomType( wkbPolygon );
    2648                 : 
    2649               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2650               1 :     oFieldAptICAO.SetWidth( 4 );
    2651               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2652                 : 
    2653               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2654               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2655                 : 
    2656               1 : }
    2657                 : 
    2658                 : /************************************************************************/
    2659                 : /*                           AddFeature()                               */
    2660                 : /************************************************************************/
    2661                 : 
    2662                 : OGRFeature*
    2663               1 :      OGRXPlaneAPTBoundaryLayer::AddFeature(const char* pszAptICAO,
    2664                 :                                            const char* pszBoundaryName,
    2665                 :                                            OGRPolygon* poPolygon)
    2666                 : {
    2667               1 :     int nCount = 0;
    2668               1 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2669                 : 
    2670               1 :     poFeature->SetGeometry( poPolygon );
    2671                 : 
    2672               1 :     poFeature->SetField( nCount++, pszAptICAO );
    2673               1 :     poFeature->SetField( nCount++, pszBoundaryName );
    2674                 : 
    2675               1 :     RegisterFeature(poFeature);
    2676                 : 
    2677               1 :     return poFeature;
    2678                 : }
    2679                 : 
    2680                 : /************************************************************************/
    2681                 : /*               OGRXPlaneAPTLinearFeatureLayer()                       */
    2682                 : /************************************************************************/
    2683                 : 
    2684                 : 
    2685               1 : OGRXPlaneAPTLinearFeatureLayer::OGRXPlaneAPTLinearFeatureLayer() : OGRXPlaneLayer("APTLinearFeature")
    2686                 : {
    2687               1 :     poFeatureDefn->SetGeomType( wkbMultiLineString );
    2688                 : 
    2689               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2690               1 :     oFieldAptICAO.SetWidth( 4 );
    2691               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2692                 : 
    2693               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2694               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2695                 : 
    2696               1 : }
    2697                 : 
    2698                 : /************************************************************************/
    2699                 : /*                           AddFeature()                               */
    2700                 : /************************************************************************/
    2701                 : 
    2702                 : OGRFeature*
    2703              45 :      OGRXPlaneAPTLinearFeatureLayer::AddFeature(const char* pszAptICAO,
    2704                 :                                                 const char* pszLinearFeatureName,
    2705                 :                                                 OGRMultiLineString* poMultilineString)
    2706                 : {
    2707              45 :     int nCount = 0;
    2708              45 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2709                 : 
    2710              45 :     poFeature->SetGeometry( poMultilineString );
    2711                 : 
    2712              45 :     poFeature->SetField( nCount++, pszAptICAO );
    2713              45 :     poFeature->SetField( nCount++, pszLinearFeatureName );
    2714                 : 
    2715              45 :     RegisterFeature(poFeature);
    2716                 : 
    2717              45 :     return poFeature;
    2718                 : }
    2719                 : 
    2720                 : /************************************************************************/
    2721                 : /*                        OGRXPlaneATCFreqLayer()                       */
    2722                 : /************************************************************************/
    2723                 : 
    2724                 : 
    2725               1 : OGRXPlaneATCFreqLayer::OGRXPlaneATCFreqLayer() : OGRXPlaneLayer("ATCFreq")
    2726                 : {
    2727               1 :     poFeatureDefn->SetGeomType( wkbNone );
    2728                 : 
    2729               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2730               1 :     oFieldAptICAO.SetWidth( 4 );
    2731               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2732                 : 
    2733               1 :     OGRFieldDefn oFieldATCFreqType("atc_type", OFTString );
    2734               1 :     oFieldATCFreqType.SetWidth( 4 );
    2735               1 :     poFeatureDefn->AddFieldDefn( &oFieldATCFreqType );
    2736                 : 
    2737               1 :     OGRFieldDefn oFieldATCFreqName("freq_name", OFTString );
    2738               1 :     poFeatureDefn->AddFieldDefn( &oFieldATCFreqName );
    2739                 : 
    2740               1 :     OGRFieldDefn oFieldFreq("freq_mhz", OFTReal );
    2741               1 :     oFieldFreq.SetWidth( 7 );
    2742               1 :     oFieldFreq.SetPrecision( 3 );
    2743               1 :     poFeatureDefn->AddFieldDefn( &oFieldFreq );
    2744               1 : }
    2745                 : 
    2746                 : /************************************************************************/
    2747                 : /*                           AddFeature()                               */
    2748                 : /************************************************************************/
    2749                 : 
    2750                 : OGRFeature*
    2751              42 :      OGRXPlaneATCFreqLayer::AddFeature (const char* pszAptICAO,
    2752                 :                                         const char* pszATCType,
    2753                 :                                         const char* pszATCFreqName,
    2754                 :                                         double dfFrequency)
    2755                 : {
    2756              42 :     int nCount = 0;
    2757              42 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2758              42 :     poFeature->SetField( nCount++, pszAptICAO );
    2759              42 :     poFeature->SetField( nCount++, pszATCType );
    2760              42 :     poFeature->SetField( nCount++, pszATCFreqName );
    2761              42 :     poFeature->SetField( nCount++, dfFrequency );
    2762                 : 
    2763              42 :     RegisterFeature(poFeature);
    2764                 : 
    2765              42 :     return poFeature;
    2766                 : }
    2767                 : 
    2768                 : 
    2769                 : /************************************************************************/
    2770                 : /*                     OGRXPlaneStartupLocationLayer()                  */
    2771                 : /************************************************************************/
    2772                 : 
    2773               1 : OGRXPlaneStartupLocationLayer::OGRXPlaneStartupLocationLayer() : OGRXPlaneLayer("StartupLocation")
    2774                 : {
    2775               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2776                 : 
    2777               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2778               1 :     oFieldAptICAO.SetWidth( 4 );
    2779               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2780                 : 
    2781               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2782               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2783                 : 
    2784               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2785               1 :     oFieldTrueHeading.SetWidth( 6 );
    2786               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2787               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2788               1 : }
    2789                 : 
    2790                 : /************************************************************************/
    2791                 : /*                           AddFeature()                               */
    2792                 : /************************************************************************/
    2793                 : 
    2794                 : OGRFeature*
    2795             110 :      OGRXPlaneStartupLocationLayer::AddFeature (const char* pszAptICAO,
    2796                 :                                                 const char* pszName,
    2797                 :                                                 double dfLat,
    2798                 :                                                 double dfLon,
    2799                 :                                                 double dfTrueHeading)
    2800                 : {
    2801             110 :     int nCount = 0;
    2802             110 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2803             110 :     poFeature->SetField( nCount++, pszAptICAO );
    2804             110 :     poFeature->SetField( nCount++, pszName );
    2805             220 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2806             110 :     poFeature->SetField( nCount++, dfTrueHeading );
    2807                 : 
    2808             110 :     RegisterFeature(poFeature);
    2809                 : 
    2810             110 :     return poFeature;
    2811                 : }
    2812                 : 
    2813                 : 
    2814                 : /************************************************************************/
    2815                 : /*                      OGRXPlaneAPTLightBeaconLayer()                  */
    2816                 : /************************************************************************/
    2817                 : 
    2818               1 : OGRXPlaneAPTLightBeaconLayer::OGRXPlaneAPTLightBeaconLayer() : OGRXPlaneLayer("APTLightBeacon")
    2819                 : {
    2820               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2821                 : 
    2822               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2823               1 :     oFieldAptICAO.SetWidth( 4 );
    2824               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2825                 : 
    2826               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2827               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2828                 : 
    2829               1 :     OGRFieldDefn oFieldColor("color", OFTString );
    2830               1 :     poFeatureDefn->AddFieldDefn( &oFieldColor );
    2831               1 : }
    2832                 : 
    2833                 : /************************************************************************/
    2834                 : /*                           AddFeature()                               */
    2835                 : /************************************************************************/
    2836                 : 
    2837                 : OGRFeature*
    2838               3 :      OGRXPlaneAPTLightBeaconLayer::AddFeature (const char* pszAptICAO,
    2839                 :                                                const char* pszName,
    2840                 :                                                double dfLat,
    2841                 :                                                double dfLon,
    2842                 :                                                const char* pszColor)
    2843                 : {
    2844               3 :     int nCount = 0;
    2845               3 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2846               3 :     poFeature->SetField( nCount++, pszAptICAO );
    2847               3 :     poFeature->SetField( nCount++, pszName );
    2848               6 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2849               3 :     poFeature->SetField( nCount++, pszColor );
    2850                 : 
    2851               3 :     RegisterFeature(poFeature);
    2852                 : 
    2853               3 :     return poFeature;
    2854                 : }
    2855                 : 
    2856                 : /************************************************************************/
    2857                 : /*                        OGRXPlaneAPTWindsockLayer()                   */
    2858                 : /************************************************************************/
    2859                 : 
    2860               1 : OGRXPlaneAPTWindsockLayer::OGRXPlaneAPTWindsockLayer() : OGRXPlaneLayer("APTWindsock")
    2861                 : {
    2862               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2863                 : 
    2864               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2865               1 :     oFieldAptICAO.SetWidth( 4 );
    2866               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2867                 : 
    2868               1 :     OGRFieldDefn oFieldName("name", OFTString );
    2869               1 :     poFeatureDefn->AddFieldDefn( &oFieldName );
    2870                 : 
    2871               1 :     OGRFieldDefn oFieldIsIlluminated("is_illuminated", OFTInteger );
    2872               1 :     oFieldIsIlluminated.SetWidth( 1 );
    2873               1 :     poFeatureDefn->AddFieldDefn( &oFieldIsIlluminated );
    2874               1 : }
    2875                 : 
    2876                 : /************************************************************************/
    2877                 : /*                           AddFeature()                               */
    2878                 : /************************************************************************/
    2879                 : 
    2880                 : OGRFeature*
    2881              25 :      OGRXPlaneAPTWindsockLayer::AddFeature (const char* pszAptICAO,
    2882                 :                                             const char* pszName,
    2883                 :                                             double dfLat,
    2884                 :                                             double dfLon,
    2885                 :                                             int bIsIllumnited)
    2886                 : {
    2887              25 :     int nCount = 0;
    2888              25 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2889              25 :     poFeature->SetField( nCount++, pszAptICAO );
    2890              25 :     poFeature->SetField( nCount++, pszName );
    2891              50 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2892              25 :     poFeature->SetField( nCount++, bIsIllumnited );
    2893                 : 
    2894              25 :     RegisterFeature(poFeature);
    2895                 : 
    2896              25 :     return poFeature;
    2897                 : }
    2898                 : 
    2899                 : 
    2900                 : /************************************************************************/
    2901                 : /*                        OGRXPlaneTaxiwaySignLayer()                   */
    2902                 : /************************************************************************/
    2903                 : 
    2904               1 : OGRXPlaneTaxiwaySignLayer::OGRXPlaneTaxiwaySignLayer() : OGRXPlaneLayer("TaxiwaySign")
    2905                 : {
    2906               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2907                 : 
    2908               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2909               1 :     oFieldAptICAO.SetWidth( 4 );
    2910               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2911                 : 
    2912               1 :     OGRFieldDefn oFieldText("text", OFTString );
    2913               1 :     poFeatureDefn->AddFieldDefn( &oFieldText );
    2914                 : 
    2915               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2916               1 :     oFieldTrueHeading.SetWidth( 6 );
    2917               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2918               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2919                 : 
    2920               1 :     OGRFieldDefn oFieldSize("size", OFTInteger );
    2921               1 :     oFieldSize.SetWidth( 1 );
    2922               1 :     poFeatureDefn->AddFieldDefn( &oFieldSize );
    2923               1 : }
    2924                 : 
    2925                 : /************************************************************************/
    2926                 : /*                           AddFeature()                               */
    2927                 : /************************************************************************/
    2928                 : 
    2929                 : OGRFeature*
    2930              17 :      OGRXPlaneTaxiwaySignLayer::AddFeature (const char* pszAptICAO,
    2931                 :                                             const char* pszText,
    2932                 :                                             double dfLat,
    2933                 :                                             double dfLon,
    2934                 :                                             double dfHeading,
    2935                 :                                             int nSize)
    2936                 : {
    2937              17 :     int nCount = 0;
    2938              17 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2939              17 :     poFeature->SetField( nCount++, pszAptICAO );
    2940              17 :     poFeature->SetField( nCount++, pszText );
    2941              34 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    2942              17 :     poFeature->SetField( nCount++, dfHeading );
    2943              17 :     poFeature->SetField( nCount++, nSize );
    2944                 : 
    2945              17 :     RegisterFeature(poFeature);
    2946                 : 
    2947              17 :     return poFeature;
    2948                 : }
    2949                 : 
    2950                 : 
    2951                 : /************************************************************************/
    2952                 : /*                   OGRXPlane_VASI_PAPI_WIGWAG_Layer()                 */
    2953                 : /************************************************************************/
    2954                 : 
    2955               1 : OGRXPlane_VASI_PAPI_WIGWAG_Layer::OGRXPlane_VASI_PAPI_WIGWAG_Layer() : OGRXPlaneLayer("VASI_PAPI_WIGWAG")
    2956                 : {
    2957               1 :     poFeatureDefn->SetGeomType( wkbPoint );
    2958                 : 
    2959               1 :     OGRFieldDefn oFieldAptICAO("apt_icao", OFTString );
    2960               1 :     oFieldAptICAO.SetWidth( 4 );
    2961               1 :     poFeatureDefn->AddFieldDefn( &oFieldAptICAO );
    2962                 : 
    2963               1 :     OGRFieldDefn oFieldRwyNum("rwy_num", OFTString );
    2964               1 :     oFieldRwyNum.SetWidth( 3 );
    2965               1 :     poFeatureDefn->AddFieldDefn( &oFieldRwyNum );
    2966                 : 
    2967               1 :     OGRFieldDefn oFieldType("type", OFTString );
    2968               1 :     poFeatureDefn->AddFieldDefn( &oFieldType );
    2969                 : 
    2970               1 :     OGRFieldDefn oFieldTrueHeading("true_heading_deg", OFTReal );
    2971               1 :     oFieldTrueHeading.SetWidth( 6 );
    2972               1 :     oFieldTrueHeading.SetPrecision( 2 );
    2973               1 :     poFeatureDefn->AddFieldDefn( &oFieldTrueHeading );
    2974                 : 
    2975               1 :     OGRFieldDefn oFieldVisualGlidePathAngle("visual_glide_deg", OFTReal );
    2976               1 :     oFieldVisualGlidePathAngle.SetWidth( 4 );
    2977               1 :     oFieldVisualGlidePathAngle.SetPrecision( 2 );
    2978               1 :     poFeatureDefn->AddFieldDefn( &oFieldVisualGlidePathAngle );
    2979               1 : }
    2980                 : 
    2981                 : /************************************************************************/
    2982                 : /*                           AddFeature()                               */
    2983                 : /************************************************************************/
    2984                 : 
    2985                 : OGRFeature*
    2986              30 :      OGRXPlane_VASI_PAPI_WIGWAG_Layer::AddFeature (const char* pszAptICAO,
    2987                 :                                                    const char* pszRwyNum,
    2988                 :                                                    const char* pszObjectType,
    2989                 :                                                    double dfLat,
    2990                 :                                                    double dfLon,
    2991                 :                                                    double dfHeading,
    2992                 :                                                    double dfVisualGlidePathAngle)
    2993                 : {
    2994              30 :     int nCount = 0;
    2995              30 :     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
    2996              30 :     poFeature->SetField( nCount++, pszAptICAO );
    2997              30 :     poFeature->SetField( nCount++, pszRwyNum );
    2998              30 :     poFeature->SetField( nCount++, pszObjectType );
    2999              60 :     poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
    3000              30 :     poFeature->SetField( nCount++, dfHeading );
    3001              30 :     poFeature->SetField( nCount++, dfVisualGlidePathAngle );
    3002                 : 
    3003              30 :     RegisterFeature(poFeature);
    3004                 : 
    3005              30 :     return poFeature;
    3006            1140 : }

Generated by: LCOV version 1.7