LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/xplane - ogr_xplane_apt_reader.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 1436
Code covered: 90.7 % Executed lines: 1303

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

Generated by: LTP GCOV extension version 1.5