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

Generated by: LCOV version 1.7