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