1 : /******************************************************************************
2 : * $Id: ogropenairlayer.cpp 20996 2010-10-28 18:38:15Z rouault $
3 : *
4 : * Project: OpenAir Translator
5 : * Purpose: Implements OGROpenAirLayer class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault <even dot rouault at mines dash 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_openair.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "ogr_p.h"
34 : #include "ogr_xplane_geo_utils.h"
35 : #include "ogr_srs_api.h"
36 :
37 : CPL_CVSID("$Id: ogropenairlayer.cpp 20996 2010-10-28 18:38:15Z rouault $");
38 :
39 : /************************************************************************/
40 : /* OGROpenAirLayer() */
41 : /************************************************************************/
42 :
43 2 : OGROpenAirLayer::OGROpenAirLayer( VSILFILE* fp )
44 :
45 : {
46 2 : fpOpenAir = fp;
47 2 : nNextFID = 0;
48 2 : bEOF = FALSE;
49 2 : bHasLastLine = FALSE;
50 :
51 2 : poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
52 :
53 4 : poFeatureDefn = new OGRFeatureDefn( "airspaces" );
54 2 : poFeatureDefn->Reference();
55 2 : poFeatureDefn->SetGeomType( wkbPolygon );
56 :
57 2 : OGRFieldDefn oField1( "CLASS", OFTString);
58 2 : poFeatureDefn->AddFieldDefn( &oField1 );
59 2 : OGRFieldDefn oField2( "NAME", OFTString);
60 2 : poFeatureDefn->AddFieldDefn( &oField2 );
61 2 : OGRFieldDefn oField3( "FLOOR", OFTString);
62 2 : poFeatureDefn->AddFieldDefn( &oField3 );
63 2 : OGRFieldDefn oField4( "CEILING", OFTString);
64 2 : poFeatureDefn->AddFieldDefn( &oField4 );
65 2 : }
66 :
67 : /************************************************************************/
68 : /* ~OGROpenAirLayer() */
69 : /************************************************************************/
70 :
71 2 : OGROpenAirLayer::~OGROpenAirLayer()
72 :
73 : {
74 2 : if( poSRS != NULL )
75 2 : poSRS->Release();
76 :
77 2 : poFeatureDefn->Release();
78 :
79 2 : std::map<CPLString,OpenAirStyle*>::const_iterator iter;
80 :
81 4 : for( iter = oStyleMap.begin(); iter != oStyleMap.end(); ++iter )
82 : {
83 2 : CPLFree(iter->second);
84 : }
85 :
86 2 : VSIFCloseL( fpOpenAir );
87 2 : }
88 :
89 :
90 : /************************************************************************/
91 : /* ResetReading() */
92 : /************************************************************************/
93 :
94 0 : void OGROpenAirLayer::ResetReading()
95 :
96 : {
97 0 : nNextFID = 0;
98 0 : bEOF = FALSE;
99 0 : bHasLastLine = FALSE;
100 0 : VSIFSeekL( fpOpenAir, 0, SEEK_SET );
101 0 : }
102 :
103 :
104 : /************************************************************************/
105 : /* GetNextFeature() */
106 : /************************************************************************/
107 :
108 6 : OGRFeature *OGROpenAirLayer::GetNextFeature()
109 : {
110 : OGRFeature *poFeature;
111 :
112 0 : while(TRUE)
113 : {
114 6 : poFeature = GetNextRawFeature();
115 6 : if (poFeature == NULL)
116 0 : return NULL;
117 :
118 6 : if((m_poFilterGeom == NULL
119 : || FilterGeometry( poFeature->GetGeometryRef() ) )
120 : && (m_poAttrQuery == NULL
121 : || m_poAttrQuery->Evaluate( poFeature )) )
122 : {
123 6 : return poFeature;
124 : }
125 : else
126 0 : delete poFeature;
127 : }
128 : }
129 :
130 : /************************************************************************/
131 : /* GetNextRawFeature() */
132 : /************************************************************************/
133 :
134 6 : OGRFeature *OGROpenAirLayer::GetNextRawFeature()
135 : {
136 : const char* pszLine;
137 6 : CPLString osCLASS, osNAME, osFLOOR, osCEILING;
138 6 : OGRLinearRing oLR;
139 6 : double dfLastLat = 0, dfLastLon = 0;
140 6 : int bFirst = TRUE;
141 6 : int bClockWise = TRUE;
142 6 : double dfCenterLat = 0, dfCenterLon = 0;
143 6 : int bHasCenter = FALSE;
144 : OpenAirStyle sStyle;
145 6 : sStyle.penStyle = -1;
146 6 : sStyle.penWidth = -1;
147 6 : sStyle.penR = sStyle.penG = sStyle.penB = -1;
148 6 : sStyle.fillR = sStyle.fillG = sStyle.fillB = -1;
149 :
150 6 : if (bEOF)
151 0 : return NULL;
152 :
153 82 : while(TRUE)
154 : {
155 94 : if (bFirst && bHasLastLine)
156 : {
157 6 : pszLine = osLastLine.c_str();
158 6 : bFirst = FALSE;
159 : }
160 : else
161 : {
162 82 : pszLine = CPLReadLine2L(fpOpenAir, 1024, NULL);
163 82 : if (pszLine == NULL)
164 : {
165 2 : bEOF = TRUE;
166 2 : if (oLR.getNumPoints() == 0)
167 0 : return NULL;
168 :
169 2 : if (osCLASS.size() != 0 &&
170 : oStyleMap.find(osCLASS) != oStyleMap.end())
171 : {
172 0 : memcpy(&sStyle, oStyleMap[osCLASS], sizeof(sStyle));
173 : }
174 2 : break;
175 : }
176 80 : osLastLine = pszLine;
177 80 : bHasLastLine = TRUE;
178 : }
179 :
180 86 : if (pszLine[0] == '*' || pszLine[0] == '\0')
181 18 : continue;
182 :
183 76 : if (EQUALN(pszLine, "AC ", 3) || EQUALN(pszLine, "AC,", 3))
184 : {
185 12 : if (osCLASS.size() != 0)
186 : {
187 8 : if (sStyle.penStyle != -1 || sStyle.fillR != -1)
188 : {
189 2 : if (oLR.getNumPoints() == 0)
190 : {
191 : OpenAirStyle* psStyle;
192 2 : if (oStyleMap.find(osCLASS) == oStyleMap.end())
193 : {
194 : psStyle = (OpenAirStyle*)CPLMalloc(
195 2 : sizeof(OpenAirStyle));
196 2 : oStyleMap[osCLASS] = psStyle;
197 : }
198 : else
199 0 : psStyle = oStyleMap[osCLASS];
200 2 : memcpy(psStyle, &sStyle, sizeof(sStyle));
201 : }
202 : else
203 0 : break;
204 : }
205 4 : else if (oStyleMap.find(osCLASS) != oStyleMap.end())
206 : {
207 2 : memcpy(&sStyle, oStyleMap[osCLASS], sizeof(sStyle));
208 2 : break;
209 : }
210 : else
211 2 : break;
212 : }
213 8 : sStyle.penStyle = -1;
214 8 : sStyle.penWidth = -1;
215 8 : sStyle.penR = sStyle.penG = sStyle.penB = -1;
216 8 : sStyle.fillR = sStyle.fillG = sStyle.fillB = -1;
217 8 : osCLASS = pszLine + 3;
218 8 : bClockWise = TRUE;
219 8 : bHasCenter = FALSE;
220 : }
221 56 : else if (EQUALN(pszLine, "AN ", 3))
222 : {
223 6 : if (osNAME.size() != 0)
224 0 : break;
225 6 : osNAME = pszLine + 3;
226 : }
227 50 : else if (EQUALN(pszLine, "AH ", 3))
228 6 : osCEILING = pszLine + 3;
229 44 : else if (EQUALN(pszLine, "AL ", 3))
230 6 : osFLOOR = pszLine + 3;
231 38 : else if (EQUALN(pszLine, "AT ", 3))
232 : {
233 : /* Ignored for that layer*/
234 : }
235 34 : else if (EQUALN(pszLine, "SP ", 3))
236 : {
237 4 : if (osCLASS.size() != 0)
238 : {
239 4 : char** papszTokens = CSLTokenizeString2(pszLine+3, ", ", 0);
240 4 : if (CSLCount(papszTokens) == 5)
241 : {
242 4 : sStyle.penStyle = atoi(papszTokens[0]);
243 4 : sStyle.penWidth = atoi(papszTokens[1]);
244 4 : sStyle.penR = atoi(papszTokens[2]);
245 4 : sStyle.penG = atoi(papszTokens[3]);
246 4 : sStyle.penB = atoi(papszTokens[4]);
247 : }
248 4 : CSLDestroy(papszTokens);
249 : }
250 : }
251 30 : else if (EQUALN(pszLine, "SB ", 3))
252 : {
253 4 : if (osCLASS.size() != 0)
254 : {
255 4 : char** papszTokens = CSLTokenizeString2(pszLine+3, ", ", 0);
256 4 : if (CSLCount(papszTokens) == 3)
257 : {
258 4 : sStyle.fillR = atoi(papszTokens[0]);
259 4 : sStyle.fillG = atoi(papszTokens[1]);
260 4 : sStyle.fillB = atoi(papszTokens[2]);
261 : }
262 4 : CSLDestroy(papszTokens);
263 : }
264 : }
265 26 : else if (EQUALN(pszLine, "DP ", 3))
266 : {
267 10 : pszLine += 3;
268 :
269 : double dfLat, dfLon;
270 10 : if (!OGROpenAirGetLatLon(pszLine, dfLat, dfLon))
271 0 : continue;
272 :
273 10 : oLR.addPoint(dfLon, dfLat);
274 10 : dfLastLat = dfLat;
275 10 : dfLastLon = dfLon;
276 : }
277 16 : else if (EQUALN(pszLine, "DA ", 3))
278 : {
279 8 : pszLine += 3;
280 :
281 8 : char* pszStar = strchr((char*)pszLine, '*');
282 8 : if (pszStar) *pszStar = 0;
283 8 : char** papszTokens = CSLTokenizeString2(pszLine, ",", 0);
284 8 : if (bHasCenter && CSLCount(papszTokens) == 3)
285 : {
286 8 : double dfRadius = atof(papszTokens[0]) * 1852;
287 8 : double dfStartAngle = atof(papszTokens[1]);
288 8 : double dfEndAngle = atof(papszTokens[2]);
289 :
290 10 : if (bClockWise && dfEndAngle < dfStartAngle)
291 2 : dfEndAngle += 360;
292 6 : else if (!bClockWise && dfStartAngle < dfEndAngle)
293 2 : dfEndAngle -= 360;
294 :
295 8 : double dfStartDistance = dfRadius;
296 8 : double dfEndDistance = dfRadius;
297 8 : int nSign = (bClockWise) ? 1 : -1;
298 : double dfAngle;
299 : double dfLat, dfLon;
300 1168 : for(dfAngle = dfStartAngle;
301 : (dfAngle - dfEndAngle) * nSign < 0;
302 : dfAngle += nSign)
303 : {
304 : double pct = (dfAngle - dfStartAngle) /
305 1160 : (dfEndAngle - dfStartAngle);
306 : double dfDist = dfStartDistance * (1-pct) +
307 1160 : dfEndDistance * pct;
308 : OGRXPlane_ExtendPosition(dfCenterLat, dfCenterLon,
309 1160 : dfDist, dfAngle, &dfLat, &dfLon);
310 1160 : oLR.addPoint(dfLon, dfLat);
311 : }
312 : OGRXPlane_ExtendPosition(dfCenterLat, dfCenterLon,
313 8 : dfEndDistance, dfEndAngle, &dfLat, &dfLon);
314 8 : oLR.addPoint(dfLon, dfLat);
315 :
316 8 : dfLastLat = oLR.getY(oLR.getNumPoints() - 1);
317 8 : dfLastLon = oLR.getX(oLR.getNumPoints() - 1);
318 : }
319 8 : CSLDestroy(papszTokens);
320 : }
321 8 : else if (EQUALN(pszLine, "DB ", 3))
322 : {
323 0 : pszLine += 3;
324 :
325 0 : char* pszStar = strchr((char*)pszLine, '*');
326 0 : if (pszStar) *pszStar = 0;
327 0 : char** papszTokens = CSLTokenizeString2(pszLine, ",", 0);
328 : double dfFirstLat, dfFirstLon;
329 : double dfSecondLat, dfSecondLon;
330 0 : if (bHasCenter && CSLCount(papszTokens) == 2 &&
331 0 : OGROpenAirGetLatLon(papszTokens[0], dfFirstLat, dfFirstLon) &&
332 0 : OGROpenAirGetLatLon(papszTokens[1], dfSecondLat, dfSecondLon))
333 : {
334 : double dfStartDistance =OGRXPlane_Distance(dfCenterLat,
335 0 : dfCenterLon, dfFirstLat, dfFirstLon);
336 : double dfEndDistance = OGRXPlane_Distance(dfCenterLat,
337 0 : dfCenterLon, dfSecondLat, dfSecondLon);
338 : double dfStartAngle = OGRXPlane_Track(dfCenterLat,
339 0 : dfCenterLon, dfFirstLat, dfFirstLon);
340 : double dfEndAngle = OGRXPlane_Track(dfCenterLat,
341 0 : dfCenterLon, dfSecondLat, dfSecondLon);
342 :
343 0 : if (bClockWise && dfEndAngle < dfStartAngle)
344 0 : dfEndAngle += 360;
345 0 : else if (!bClockWise && dfStartAngle < dfEndAngle)
346 0 : dfEndAngle -= 360;
347 :
348 0 : int nSign = (bClockWise) ? 1 : -1;
349 : double dfAngle;
350 0 : for(dfAngle = dfStartAngle;
351 : (dfAngle - dfEndAngle) * nSign < 0;
352 : dfAngle += nSign)
353 : {
354 : double dfLat, dfLon;
355 : double pct = (dfAngle - dfStartAngle) /
356 0 : (dfEndAngle - dfStartAngle);
357 : double dfDist = dfStartDistance * (1-pct) +
358 0 : dfEndDistance * pct;
359 : OGRXPlane_ExtendPosition(dfCenterLat, dfCenterLon,
360 0 : dfDist, dfAngle, &dfLat, &dfLon);
361 0 : oLR.addPoint(dfLon, dfLat);
362 : }
363 0 : oLR.addPoint(dfSecondLon, dfSecondLat);
364 :
365 0 : dfLastLat = oLR.getY(oLR.getNumPoints() - 1);
366 0 : dfLastLon = oLR.getX(oLR.getNumPoints() - 1);
367 : }
368 0 : CSLDestroy(papszTokens);
369 : }
370 10 : else if ((EQUALN(pszLine, "DC ", 3) || EQUALN(pszLine, "DC=", 3)) &&
371 : (bHasCenter || strstr(pszLine, "V X=") != NULL))
372 : {
373 2 : if (!bHasCenter)
374 : {
375 0 : const char* pszVX = strstr(pszLine, "V X=");
376 0 : bHasCenter = OGROpenAirGetLatLon(pszVX, dfCenterLat, dfCenterLon);
377 : }
378 2 : if (bHasCenter)
379 : {
380 2 : pszLine += 3;
381 :
382 2 : double dfRADIUS = atof(pszLine) * 1852;
383 :
384 : double dfAngle;
385 : double dfLat, dfLon;
386 722 : for(dfAngle = 0; dfAngle < 360; dfAngle += 1)
387 : {
388 : OGRXPlane_ExtendPosition(dfCenterLat, dfCenterLon,
389 720 : dfRADIUS, dfAngle, &dfLat, &dfLon);
390 720 : oLR.addPoint(dfLon, dfLat);
391 : }
392 : OGRXPlane_ExtendPosition(dfCenterLat, dfCenterLon,
393 2 : dfRADIUS, 0, &dfLat, &dfLon);
394 2 : oLR.addPoint(dfLon, dfLat);
395 :
396 2 : dfLastLat = oLR.getY(oLR.getNumPoints() - 1);
397 2 : dfLastLon = oLR.getX(oLR.getNumPoints() - 1);
398 : }
399 : }
400 6 : else if (EQUALN(pszLine, "V X=", 4))
401 : {
402 : bHasCenter =
403 4 : OGROpenAirGetLatLon(pszLine + 4, dfCenterLat, dfCenterLon);
404 : }
405 2 : else if (EQUALN(pszLine, "V D=-", 5))
406 : {
407 2 : bClockWise = FALSE;
408 : }
409 0 : else if (EQUALN(pszLine, "V D=+", 5))
410 : {
411 0 : bClockWise = TRUE;
412 : }
413 : else
414 : {
415 : //CPLDebug("OpenAir", "Unexpected content : %s", pszLine);
416 : }
417 : }
418 :
419 6 : OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
420 12 : poFeature->SetField(0, osCLASS.c_str());
421 6 : poFeature->SetField(1, osNAME.c_str());
422 6 : poFeature->SetField(2, osFLOOR.c_str());
423 6 : poFeature->SetField(3, osCEILING.c_str());
424 :
425 6 : if (sStyle.penStyle != -1 || sStyle.fillR != -1)
426 : {
427 4 : CPLString osStyle;
428 4 : if (sStyle.penStyle != -1)
429 : {
430 : osStyle += CPLString().Printf("PEN(c:#%02X%02X%02X,w:%dpt",
431 : sStyle.penR, sStyle.penG, sStyle.penB,
432 4 : sStyle.penWidth);
433 4 : if (sStyle.penStyle == 1)
434 2 : osStyle += ",p:\"5px 5px\"";
435 4 : osStyle += ")";
436 : }
437 4 : if (sStyle.fillR != -1)
438 : {
439 4 : if (osStyle.size() != 0)
440 4 : osStyle += ";";
441 : osStyle += CPLString().Printf("BRUSH(fc:#%02X%02X%02X)",
442 4 : sStyle.fillR, sStyle.fillG, sStyle.fillB);
443 : }
444 : else
445 : {
446 0 : if (osStyle.size() != 0)
447 0 : osStyle += ";";
448 0 : osStyle += "BRUSH(fc:#00000000,id:\"ogr-brush-1\")";
449 : }
450 4 : if (osStyle.size() != 0)
451 4 : poFeature->SetStyleString(osStyle);
452 : }
453 :
454 6 : OGRPolygon* poPoly = new OGRPolygon();
455 6 : oLR.closeRings();
456 6 : poPoly->addRing(&oLR);
457 6 : poPoly->assignSpatialReference(poSRS);
458 6 : poFeature->SetGeometryDirectly(poPoly);
459 6 : poFeature->SetFID(nNextFID++);
460 :
461 6 : return poFeature;
462 : }
463 : /************************************************************************/
464 : /* TestCapability() */
465 : /************************************************************************/
466 :
467 0 : int OGROpenAirLayer::TestCapability( const char * pszCap )
468 :
469 : {
470 0 : return FALSE;
471 : }
472 :
|