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