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