LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/xplane - ogr_xplane_apt_reader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1466 1325 90.4 %
Date: 2011-12-18 Functions: 90 67 74.4 %

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

Generated by: LCOV version 1.7