1 /******************************************************************************
2 * $Id: ogr_xplane_awy_reader.cpp
3 *
4 * Project: X-Plane awy.dat file reader
5 * Purpose: Implements OGRXPlaneAwyReader class
6 * Author: Even Rouault, even dot rouault at mines dash paris dot org
7 *
8 ******************************************************************************
9 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at mines-paris dot org>
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_awy_reader.h"
31
32 CPL_CVSID("$Id: ogr_xplane_awy_reader.cpp 27044 2014-03-16 23:41:27Z rouault $");
33
34 /************************************************************************/
35 /* OGRXPlaneCreateAwyFileReader */
36 /************************************************************************/
37
OGRXPlaneCreateAwyFileReader(OGRXPlaneDataSource * poDataSource)38 OGRXPlaneReader* OGRXPlaneCreateAwyFileReader( OGRXPlaneDataSource* poDataSource )
39 {
40 OGRXPlaneReader* poReader = new OGRXPlaneAwyReader(poDataSource);
41 return poReader;
42 }
43
44
45 /************************************************************************/
46 /* OGRXPlaneAwyReader() */
47 /************************************************************************/
OGRXPlaneAwyReader()48 OGRXPlaneAwyReader::OGRXPlaneAwyReader()
49 {
50 poAirwaySegmentLayer = NULL;
51 poAirwayIntersectionLayer = NULL;
52 }
53
54 /************************************************************************/
55 /* OGRXPlaneAwyReader() */
56 /************************************************************************/
57
OGRXPlaneAwyReader(OGRXPlaneDataSource * poDataSource)58 OGRXPlaneAwyReader::OGRXPlaneAwyReader( OGRXPlaneDataSource* poDataSource )
59 {
60 poAirwaySegmentLayer = new OGRXPlaneAirwaySegmentLayer();
61 poAirwayIntersectionLayer = new OGRXPlaneAirwayIntersectionLayer();
62
63 poDataSource->RegisterLayer(poAirwaySegmentLayer);
64 poDataSource->RegisterLayer(poAirwayIntersectionLayer);
65 }
66
67 /************************************************************************/
68 /* CloneForLayer() */
69 /************************************************************************/
70
CloneForLayer(OGRXPlaneLayer * poLayer)71 OGRXPlaneReader* OGRXPlaneAwyReader::CloneForLayer(OGRXPlaneLayer* poLayer)
72 {
73 OGRXPlaneAwyReader* poReader = new OGRXPlaneAwyReader();
74
75 poReader->poInterestLayer = poLayer;
76
77 SET_IF_INTEREST_LAYER(poAirwaySegmentLayer);
78 SET_IF_INTEREST_LAYER(poAirwayIntersectionLayer);
79
80 if (pszFilename)
81 {
82 poReader->pszFilename = CPLStrdup(pszFilename);
83 poReader->fp = VSIFOpenL( pszFilename, "rt" );
84 }
85
86 return poReader;
87 }
88
89
90 /************************************************************************/
91 /* IsRecognizedVersion() */
92 /************************************************************************/
93
IsRecognizedVersion(const char * pszVersionString)94 int OGRXPlaneAwyReader::IsRecognizedVersion( const char* pszVersionString)
95 {
96 return EQUALN(pszVersionString, "640 Version", 11);
97 }
98
99
100 /************************************************************************/
101 /* Read() */
102 /************************************************************************/
103
Read()104 void OGRXPlaneAwyReader::Read()
105 {
106 const char* pszLine;
107 while((pszLine = CPLReadLineL(fp)) != NULL)
108 {
109 papszTokens = CSLTokenizeString(pszLine);
110 nTokens = CSLCount(papszTokens);
111
112 nLineNumber ++;
113
114 if (nTokens == 1 && strcmp(papszTokens[0], "99") == 0)
115 {
116 CSLDestroy(papszTokens);
117 papszTokens = NULL;
118 bEOF = TRUE;
119 return;
120 }
121 else if (nTokens == 0 || assertMinCol(10) == FALSE)
122 {
123 CSLDestroy(papszTokens);
124 papszTokens = NULL;
125 continue;
126 }
127
128 ParseRecord();
129
130 CSLDestroy(papszTokens);
131 papszTokens = NULL;
132
133 if (poInterestLayer && poInterestLayer->IsEmpty() == FALSE)
134 return;
135 }
136
137 papszTokens = NULL;
138 bEOF = TRUE;
139 }
140
141 /************************************************************************/
142 /* ParseRecord() */
143 /************************************************************************/
144
ParseRecord()145 void OGRXPlaneAwyReader::ParseRecord()
146 {
147 const char* pszFirstPointName;
148 const char* pszSecondPointName;
149 const char* pszAirwaySegmentName;
150 double dfLat1, dfLon1;
151 double dfLat2, dfLon2;
152 int bIsHigh;
153 int nBaseFL, nTopFL;
154
155 pszFirstPointName = papszTokens[0];
156 RET_IF_FAIL(readLatLon(&dfLat1, &dfLon1, 1));
157 pszSecondPointName = papszTokens[3];
158 RET_IF_FAIL(readLatLon(&dfLat2, &dfLon2, 4));
159 bIsHigh = atoi(papszTokens[6]) == 2;
160 nBaseFL = atoi(papszTokens[7]);
161 nTopFL = atoi(papszTokens[8]);
162 pszAirwaySegmentName = papszTokens[9];
163
164 if (poAirwayIntersectionLayer)
165 {
166 poAirwayIntersectionLayer->AddFeature(pszFirstPointName, dfLat1, dfLon1);
167 poAirwayIntersectionLayer->AddFeature(pszSecondPointName, dfLat2, dfLon2);
168 }
169
170 if (poAirwaySegmentLayer)
171 {
172 /*
173 poAirwaySegmentLayer->AddFeature(pszAirwaySegmentName,
174 pszFirstPointName,
175 pszSecondPointName,
176 dfLat1, dfLon1, dfLat2, dfLon2,
177 bIsHigh, nBaseFL, nTopFL);
178 */
179 if (strchr(pszAirwaySegmentName, '-'))
180 {
181 char** papszSegmentNames = CSLTokenizeString2( pszAirwaySegmentName, "-", CSLT_HONOURSTRINGS );
182 int i = 0;
183 while(papszSegmentNames[i])
184 {
185 poAirwaySegmentLayer->AddFeature(papszSegmentNames[i],
186 pszFirstPointName,
187 pszSecondPointName,
188 dfLat1, dfLon1, dfLat2, dfLon2,
189 bIsHigh, nBaseFL, nTopFL);
190 i++;
191 }
192 CSLDestroy(papszSegmentNames);
193 }
194 else
195 {
196 poAirwaySegmentLayer->AddFeature(pszAirwaySegmentName,
197 pszFirstPointName,
198 pszSecondPointName,
199 dfLat1, dfLon1, dfLat2, dfLon2,
200 bIsHigh, nBaseFL, nTopFL);
201 }
202 }
203 }
204
205
206 /************************************************************************/
207 /* OGRXPlaneAirwaySegmentLayer() */
208 /************************************************************************/
209
OGRXPlaneAirwaySegmentLayer()210 OGRXPlaneAirwaySegmentLayer::OGRXPlaneAirwaySegmentLayer() : OGRXPlaneLayer("AirwaySegment")
211 {
212 poFeatureDefn->SetGeomType( wkbLineString );
213
214 OGRFieldDefn oFieldSegmentName("segment_name", OFTString );
215 poFeatureDefn->AddFieldDefn( &oFieldSegmentName );
216
217 OGRFieldDefn oFieldPoint1Name("point1_name", OFTString );
218 poFeatureDefn->AddFieldDefn( &oFieldPoint1Name );
219
220 OGRFieldDefn oFieldPoint2Name("point2_name", OFTString );
221 poFeatureDefn->AddFieldDefn( &oFieldPoint2Name );
222
223 OGRFieldDefn oFieldIsHigh("is_high", OFTInteger );
224 oFieldIsHigh.SetWidth( 1 );
225 poFeatureDefn->AddFieldDefn( &oFieldIsHigh );
226
227 OGRFieldDefn oFieldBase("base_FL", OFTInteger );
228 oFieldBase.SetWidth( 3 );
229 poFeatureDefn->AddFieldDefn( &oFieldBase );
230
231 OGRFieldDefn oFieldTop("top_FL", OFTInteger );
232 oFieldTop.SetWidth( 3 );
233 poFeatureDefn->AddFieldDefn( &oFieldTop );
234 }
235
236 /************************************************************************/
237 /* AddFeature() */
238 /************************************************************************/
239
240 OGRFeature*
AddFeature(const char * pszAirwaySegmentName,const char * pszFirstPointName,const char * pszSecondPointName,double dfLat1,double dfLon1,double dfLat2,double dfLon2,int bIsHigh,int nBaseFL,int nTopFL)241 OGRXPlaneAirwaySegmentLayer::AddFeature(const char* pszAirwaySegmentName,
242 const char* pszFirstPointName,
243 const char* pszSecondPointName,
244 double dfLat1,
245 double dfLon1,
246 double dfLat2,
247 double dfLon2,
248 int bIsHigh,
249 int nBaseFL,
250 int nTopFL)
251 {
252 int nCount = 0;
253 OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
254 if (fabs(dfLon1 - dfLon2) < 270)
255 {
256 OGRLineString* lineString = new OGRLineString();
257 lineString->addPoint(dfLon1, dfLat1);
258 lineString->addPoint(dfLon2, dfLat2);
259 poFeature->SetGeometryDirectly( lineString );
260 }
261 else
262 {
263 /* Crossing antemeridian */
264 OGRMultiLineString* multiLineString = new OGRMultiLineString();
265 OGRLineString* lineString1 = new OGRLineString();
266 OGRLineString* lineString2 = new OGRLineString();
267 double dfLatInt;
268 lineString1->addPoint(dfLon1, dfLat1);
269 if (dfLon1 < dfLon2)
270 {
271 dfLatInt = dfLat1 + (dfLat2 - dfLat1) * (-180 - dfLon1) / ((dfLon2 - 360) - dfLon1);
272 lineString1->addPoint(-180, dfLatInt);
273 lineString2->addPoint(180, dfLatInt);
274 }
275 else
276 {
277 dfLatInt = dfLat1 + (dfLat2 - dfLat1) * (180 - dfLon1) / ((dfLon2 + 360) - dfLon1);
278 lineString1->addPoint(180, dfLatInt);
279 lineString2->addPoint(-180, dfLatInt);
280 }
281 lineString2->addPoint(dfLon2, dfLat2);
282 multiLineString->addGeometryDirectly( lineString1 );
283 multiLineString->addGeometryDirectly( lineString2 );
284 poFeature->SetGeometryDirectly( multiLineString );
285 }
286 poFeature->SetField( nCount++, pszAirwaySegmentName );
287 poFeature->SetField( nCount++, pszFirstPointName );
288 poFeature->SetField( nCount++, pszSecondPointName );
289 poFeature->SetField( nCount++, bIsHigh );
290 poFeature->SetField( nCount++, nBaseFL );
291 poFeature->SetField( nCount++, nTopFL );
292
293 RegisterFeature(poFeature);
294
295 return poFeature;
296 }
297
298 /************************************************************************/
299 /* EqualAirwayIntersectionFeature */
300 /************************************************************************/
301
EqualAirwayIntersectionFeatureFunc(const void * _feature1,const void * _feature2)302 static int EqualAirwayIntersectionFeatureFunc(const void* _feature1, const void* _feature2)
303 {
304 OGRFeature* feature1 = (OGRFeature*)_feature1;
305 OGRFeature* feature2 = (OGRFeature*)_feature2;
306 if (strcmp(feature1->GetFieldAsString(0), feature2->GetFieldAsString(0)) == 0)
307 {
308 OGRPoint* point1 = (OGRPoint*) feature1->GetGeometryRef();
309 OGRPoint* point2 = (OGRPoint*) feature2->GetGeometryRef();
310 return (point1->getX() == point2->getX() && point1->getY() == point2->getY());
311 }
312 return FALSE;
313 }
314
315
316 /************************************************************************/
317 /* OGRXPlaneAirwayHashDouble() */
318 /************************************************************************/
319
OGRXPlaneAirwayHashDouble(const double & dfVal)320 static unsigned long OGRXPlaneAirwayHashDouble(const double& dfVal)
321 {
322 /* To make a long story short, we must copy the double into */
323 /* an array in order to respect C strict-aliasing rule */
324 /* We can't directly cast into an unsigned int* */
325 /* See #2521 for the longer version */
326 unsigned int anValue[2];
327 memcpy(anValue, &dfVal, sizeof(double));
328 return anValue[0] ^ anValue[1];
329 }
330
331 /************************************************************************/
332 /* HashAirwayIntersectionFeatureFunc */
333 /************************************************************************/
334
HashAirwayIntersectionFeatureFunc(const void * _feature)335 static unsigned long HashAirwayIntersectionFeatureFunc(const void* _feature)
336 {
337 OGRFeature* feature = (OGRFeature*)_feature;
338 OGRPoint* point = (OGRPoint*) feature->GetGeometryRef();
339 unsigned long hash = CPLHashSetHashStr((unsigned char*)feature->GetFieldAsString(0));
340 const double x = point->getX();
341 const double y = point->getY();
342 return hash ^ OGRXPlaneAirwayHashDouble(x) ^ OGRXPlaneAirwayHashDouble(y);
343 }
344
345 /************************************************************************/
346 /* FreeAirwayIntersectionFeatureFunc */
347 /************************************************************************/
348
FreeAirwayIntersectionFeatureFunc(void * _feature)349 static void FreeAirwayIntersectionFeatureFunc(void* _feature)
350 {
351 delete (OGRFeature*)_feature;
352 }
353
354 /************************************************************************/
355 /* OGRXPlaneAirwayIntersectionLayer() */
356 /************************************************************************/
357
OGRXPlaneAirwayIntersectionLayer()358 OGRXPlaneAirwayIntersectionLayer::OGRXPlaneAirwayIntersectionLayer() : OGRXPlaneLayer("AirwayIntersection")
359 {
360 poFeatureDefn->SetGeomType( wkbPoint );
361
362 OGRFieldDefn oFieldName("name", OFTString );
363 poFeatureDefn->AddFieldDefn( &oFieldName );
364
365 poSet = CPLHashSetNew(HashAirwayIntersectionFeatureFunc,
366 EqualAirwayIntersectionFeatureFunc,
367 FreeAirwayIntersectionFeatureFunc);
368 }
369
370 /************************************************************************/
371 /* ~OGRXPlaneAirwayIntersectionLayer() */
372 /************************************************************************/
373
~OGRXPlaneAirwayIntersectionLayer()374 OGRXPlaneAirwayIntersectionLayer::~OGRXPlaneAirwayIntersectionLayer()
375 {
376 CPLHashSetDestroy(poSet);
377 }
378
379 /************************************************************************/
380 /* AddFeature() */
381 /************************************************************************/
382
383 OGRFeature*
AddFeature(const char * pszIntersectionName,double dfLat,double dfLon)384 OGRXPlaneAirwayIntersectionLayer::AddFeature(const char* pszIntersectionName,
385 double dfLat,
386 double dfLon)
387 {
388 OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
389 poFeature->SetGeometryDirectly( new OGRPoint( dfLon, dfLat ) );
390 poFeature->SetField( 0, pszIntersectionName );
391
392 if (CPLHashSetLookup(poSet, poFeature) == NULL)
393 {
394 CPLHashSetInsert(poSet, poFeature->Clone());
395 RegisterFeature(poFeature);
396
397 return poFeature;
398 }
399 else
400 {
401 delete poFeature;
402 return NULL;
403 }
404 }
405
406 /************************************************************************/
407 /* ResetReading() */
408 /************************************************************************/
409
ResetReading()410 void OGRXPlaneAirwayIntersectionLayer::ResetReading()
411 {
412 if (poReader)
413 {
414 CPLHashSetDestroy(poSet);
415 poSet = CPLHashSetNew(HashAirwayIntersectionFeatureFunc,
416 EqualAirwayIntersectionFeatureFunc,
417 FreeAirwayIntersectionFeatureFunc);
418 }
419
420 OGRXPlaneLayer::ResetReading();
421 }
422