forked from OSGeo/gdal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathogr_srs_ozi.cpp
506 lines (462 loc) · 19.1 KB
/
ogr_srs_ozi.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
/******************************************************************************
*
* Project: OpenGIS Simple Features Reference Implementation
* Purpose: OGRSpatialReference translation from OziExplorer
* georeferencing information.
* Author: Andrey Kiselev, [email protected]
*
******************************************************************************
* Copyright (c) 2009, Andrey Kiselev <[email protected]>
* Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
****************************************************************************/
#include "cpl_port.h"
#include "ogr_spatialref.h"
#include <cstdlib>
#include <cstring>
#include "cpl_conv.h"
#include "cpl_csv.h"
#include "cpl_error.h"
#include "cpl_string.h"
#include "ogr_core.h"
#include "ogr_srs_api.h"
CPL_CVSID("$Id$")
/************************************************************************/
/* OSRImportFromOzi() */
/************************************************************************/
/**
* Import coordinate system from OziExplorer projection definition.
*
* This function will import projection definition in style, used by
* OziExplorer software.
*
* Note: another version of this function with a different signature existed
* in GDAL 1.X.
*
* @param hSRS spatial reference object.
* @param papszLines Map file lines. This is an array of strings containing
* the whole OziExplorer .MAP file. The array is terminated by a NULL pointer.
*
* @return OGRERR_NONE on success or an error code in case of failure.
*
* @since OGR 2.0
*/
OGRErr OSRImportFromOzi( OGRSpatialReferenceH hSRS,
const char * const* papszLines )
{
VALIDATE_POINTER1( hSRS, "OSRImportFromOzi", OGRERR_FAILURE );
return OGRSpatialReference::FromHandle(hSRS)->importFromOzi( papszLines );
}
/************************************************************************/
/* importFromOzi() */
/************************************************************************/
/**
* Import coordinate system from OziExplorer projection definition.
*
* This method will import projection definition in style, used by
* OziExplorer software.
*
* @param papszLines Map file lines. This is an array of strings containing
* the whole OziExplorer .MAP file. The array is terminated by a NULL pointer.
*
* @return OGRERR_NONE on success or an error code in case of failure.
*
* @since OGR 1.10
*/
OGRErr OGRSpatialReference::importFromOzi( const char * const* papszLines )
{
const char *pszDatum;
const char *pszProj = nullptr;
const char *pszProjParams = nullptr;
Clear();
const int nLines = CSLCount(papszLines);
if( nLines < 5 )
return OGRERR_NOT_ENOUGH_DATA;
pszDatum = papszLines[4];
for( int iLine = 5; iLine < nLines; iLine++ )
{
if( STARTS_WITH_CI(papszLines[iLine], "Map Projection") )
{
pszProj = papszLines[iLine];
}
else if( STARTS_WITH_CI(papszLines[iLine], "Projection Setup") )
{
pszProjParams = papszLines[iLine];
}
}
if( !(pszDatum && pszProj && pszProjParams) )
return OGRERR_NOT_ENOUGH_DATA;
/* -------------------------------------------------------------------- */
/* Operate on the basis of the projection name. */
/* -------------------------------------------------------------------- */
char **papszProj = CSLTokenizeStringComplex( pszProj, ",", TRUE, TRUE );
char **papszProjParams = CSLTokenizeStringComplex( pszProjParams, ",",
TRUE, TRUE );
char **papszDatum = nullptr;
if( CSLCount(papszProj) < 2 )
{
goto not_enough_data;
}
if( STARTS_WITH_CI(papszProj[1], "Latitude/Longitude") )
{
// Do nothing.
}
else if( STARTS_WITH_CI(papszProj[1], "Mercator") )
{
if( CSLCount(papszProjParams) < 6 ) goto not_enough_data;
double dfScale = CPLAtof(papszProjParams[3]);
// If unset, default to scale = 1.
if( papszProjParams[3][0] == 0 ) dfScale = 1;
SetMercator( CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
dfScale,
CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]) );
}
else if( STARTS_WITH_CI(papszProj[1], "Transverse Mercator") )
{
if( CSLCount(papszProjParams) < 6 ) goto not_enough_data;
SetTM( CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
CPLAtof(papszProjParams[3]),
CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]) );
}
else if( STARTS_WITH_CI(papszProj[1], "Lambert Conformal Conic") )
{
if( CSLCount(papszProjParams) < 8 ) goto not_enough_data;
SetLCC( CPLAtof(papszProjParams[6]), CPLAtof(papszProjParams[7]),
CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]) );
}
else if( STARTS_WITH_CI(papszProj[1], "Sinusoidal") )
{
if( CSLCount(papszProjParams) < 6 ) goto not_enough_data;
SetSinusoidal( CPLAtof(papszProjParams[2]),
CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]) );
}
else if( STARTS_WITH_CI(papszProj[1], "Albers Equal Area") )
{
if( CSLCount(papszProjParams) < 8 ) goto not_enough_data;
SetACEA( CPLAtof(papszProjParams[6]), CPLAtof(papszProjParams[7]),
CPLAtof(papszProjParams[1]), CPLAtof(papszProjParams[2]),
CPLAtof(papszProjParams[4]), CPLAtof(papszProjParams[5]) );
}
else if( STARTS_WITH_CI(
papszProj[1], "(UTM) Universal Transverse Mercator") &&
nLines > 5 )
{
// Look for the UTM zone in the calibration point data.
int iLine = 5; // Used after for.
for( ; iLine < nLines; iLine++ )
{
if( STARTS_WITH_CI(papszLines[iLine], "Point") )
{
char **papszTok =
CSLTokenizeString2(papszLines[iLine], ",",
CSLT_ALLOWEMPTYTOKENS
| CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES);
if( CSLCount(papszTok) < 17
|| EQUAL(papszTok[2], "")
|| EQUAL(papszTok[13], "")
|| EQUAL(papszTok[14], "")
|| EQUAL(papszTok[15], "")
|| EQUAL(papszTok[16], "") )
{
CSLDestroy(papszTok);
continue;
}
SetUTM( atoi(papszTok[13]), EQUAL(papszTok[16], "N") );
CSLDestroy(papszTok);
break;
}
}
if( iLine == nLines ) // Try to guess the UTM zone.
{
float fMinLongitude = 1000.0f;
float fMaxLongitude = -1000.0f;
float fMinLatitude = 1000.0f;
float fMaxLatitude = -1000.0f;
bool bFoundMMPLL = false;
for( iLine = 5; iLine < nLines; iLine++ )
{
if( STARTS_WITH_CI(papszLines[iLine], "MMPLL") )
{
char **papszTok =
CSLTokenizeString2(papszLines[iLine], ",",
CSLT_ALLOWEMPTYTOKENS
| CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES);
if( CSLCount(papszTok) < 4 )
{
CSLDestroy(papszTok);
continue;
}
const float fLongitude =
static_cast<float>(CPLAtofM(papszTok[2]));
const float fLatitude =
static_cast<float>(CPLAtofM(papszTok[3]));
CSLDestroy(papszTok);
bFoundMMPLL = true;
if( fMinLongitude > fLongitude )
fMinLongitude = fLongitude;
if( fMaxLongitude < fLongitude )
fMaxLongitude = fLongitude;
if( fMinLatitude > fLatitude )
fMinLatitude = fLatitude;
if( fMaxLatitude < fLatitude )
fMaxLatitude = fLatitude;
}
}
const float fMedianLatitude = (fMinLatitude + fMaxLatitude) / 2;
const float fMedianLongitude = (fMinLongitude + fMaxLongitude) / 2;
if( bFoundMMPLL && fMaxLatitude <= 90 )
{
int nUtmZone = 0;
if( fMedianLatitude >= 56 && fMedianLatitude <= 64 &&
fMedianLongitude >= 3 && fMedianLongitude <= 12 )
nUtmZone = 32; // Norway exception.
else if( fMedianLatitude >= 72 && fMedianLatitude <= 84 &&
fMedianLongitude >= 0 && fMedianLongitude <= 42 )
// Svalbard exception.
nUtmZone =
static_cast<int>((fMedianLongitude + 3) / 12) * 2 + 31;
else
nUtmZone =
static_cast<int>((fMedianLongitude + 180 ) / 6) + 1;
SetUTM( nUtmZone, fMedianLatitude >= 0 );
}
else
{
CPLDebug( "OSR_Ozi", "UTM Zone not found");
}
}
}
else if( STARTS_WITH_CI(papszProj[1], "(I) France Zone I") )
{
SetLCC1SP( 49.5, 2.337229167, 0.99987734, 600000, 1200000 );
}
else if( STARTS_WITH_CI(papszProj[1], "(II) France Zone II") )
{
SetLCC1SP( 46.8, 2.337229167, 0.99987742, 600000, 2200000 );
}
else if( STARTS_WITH_CI(papszProj[1], "(III) France Zone III") )
{
SetLCC1SP( 44.1, 2.337229167, 0.99987750, 600000, 3200000 );
}
else if( STARTS_WITH_CI(papszProj[1], "(IV) France Zone IV") )
{
SetLCC1SP( 42.165, 2.337229167, 0.99994471, 234.358, 4185861.369 );
}
/*
* Note: The following projections have not been implemented yet
*
*/
/*
else if( STARTS_WITH_CI(papszProj[1], "(BNG) British National Grid") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(IG) Irish Grid") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(NZG) New Zealand Grid") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(NZTM2) New Zealand TM 2000") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(SG) Swedish Grid") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(SUI) Swiss Grid") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(A)Lambert Azimuthual Equal Area") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(EQC) Equidistant Conic") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "Polyconic (American)") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "Van Der Grinten") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "Vertical Near-Sided Perspective") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "(WIV) Wagner IV") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "Bonne") )
{
}
else if( STARTS_WITH_CI(papszProj[1],
"(MT0) Montana State Plane Zone 2500") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "ITA1) Italy Grid Zone 1") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "ITA2) Italy Grid Zone 2") )
{
}
else if( STARTS_WITH_CI(papszProj[1],
"(VICMAP-TM) Victoria Aust.(pseudo AMG)") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "VICGRID) Victoria Australia") )
{
}
else if( STARTS_WITH_CI(papszProj[1],
"(VG94) VICGRID94 Victoria Australia") )
{
}
else if( STARTS_WITH_CI(papszProj[1], "Gnomonic") )
{
}
*/
else
{
CPLDebug( "OSR_Ozi", "Unsupported projection: \"%s\"", papszProj[1] );
SetLocalCS( CPLString().Printf(R"("Ozi" projection "%s")",
papszProj[1]) );
}
/* -------------------------------------------------------------------- */
/* Try to translate the datum/spheroid. */
/* -------------------------------------------------------------------- */
papszDatum = CSLTokenizeString2( pszDatum, ",",
CSLT_ALLOWEMPTYTOKENS
| CSLT_STRIPLEADSPACES
| CSLT_STRIPENDSPACES );
if( papszDatum == nullptr )
goto not_enough_data;
if( !IsLocal() )
{
/* -------------------------------------------------------------------- */
/* Verify that we can find the CSV file containing the datums */
/* -------------------------------------------------------------------- */
if( CSVScanFileByName( CSVFilename( "ozi_datum.csv" ),
"EPSG_DATUM_CODE",
"4326", CC_Integer ) == nullptr )
{
CPLError(CE_Failure, CPLE_OpenFailed,
"Unable to open OZI support file %s. "
"Try setting the GDAL_DATA environment variable to point "
"to the directory containing OZI csv files.",
CSVFilename( "ozi_datum.csv" ));
goto other_error;
}
/* -------------------------------------------------------------------- */
/* Search for matching datum */
/* -------------------------------------------------------------------- */
const char *pszOziDatum = CSVFilename( "ozi_datum.csv" );
CPLString osDName = CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "NAME" );
if( osDName.empty() )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to find datum %s in ozi_datum.csv.",
papszDatum[0] );
goto other_error;
}
const int nDatumCode =
atoi( CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "EPSG_DATUM_CODE" ) );
if( nDatumCode > 0 ) // There is a matching EPSG code
{
OGRSpatialReference oGCS;
oGCS.importFromEPSG( nDatumCode );
CopyGeogCSFrom( &oGCS );
}
else // We use the parameters from the CSV files
{
CPLString osEllipseCode =
CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "ELLIPSOID_CODE" );
const double dfDeltaX =
CPLAtof(CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "DELTAX" ) );
const double dfDeltaY =
CPLAtof(CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "DELTAY" ) );
const double dfDeltaZ =
CPLAtof(CSVGetField( pszOziDatum, "NAME", papszDatum[0],
CC_ApproxString, "DELTAZ" ) );
/* -------------------------------------------------------------------- */
/* Verify that we can find the CSV file containing the ellipsoids. */
/* -------------------------------------------------------------------- */
if( CSVScanFileByName( CSVFilename( "ozi_ellips.csv" ),
"ELLIPSOID_CODE",
"20", CC_Integer ) == nullptr )
{
CPLError(
CE_Failure, CPLE_OpenFailed,
"Unable to open OZI support file %s. "
"Try setting the GDAL_DATA environment variable to point "
"to the directory containing OZI csv files.",
CSVFilename( "ozi_ellips.csv" ) );
goto other_error;
}
/* -------------------------------------------------------------------- */
/* Lookup the ellipse code. */
/* -------------------------------------------------------------------- */
const char *pszOziEllipse = CSVFilename( "ozi_ellips.csv" );
CPLString osEName =
CSVGetField( pszOziEllipse, "ELLIPSOID_CODE", osEllipseCode,
CC_ApproxString, "NAME" );
if( osEName.empty() )
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to find ellipsoid %s in ozi_ellips.csv.",
osEllipseCode.c_str() );
goto other_error;
}
const double dfA =
CPLAtof(CSVGetField( pszOziEllipse, "ELLIPSOID_CODE",
osEllipseCode, CC_ApproxString, "A" ));
const double dfInvF =
CPLAtof(CSVGetField( pszOziEllipse, "ELLIPSOID_CODE",
osEllipseCode, CC_ApproxString, "INVF" ));
/* -------------------------------------------------------------------- */
/* Create geographic coordinate system. */
/* -------------------------------------------------------------------- */
SetGeogCS( osDName, osDName, osEName, dfA, dfInvF );
SetTOWGS84( dfDeltaX, dfDeltaY, dfDeltaZ );
}
}
/* -------------------------------------------------------------------- */
/* Grid units translation */
/* -------------------------------------------------------------------- */
if( IsLocal() || IsProjected() )
SetLinearUnits( SRS_UL_METER, 1.0 );
CSLDestroy(papszProj);
CSLDestroy(papszProjParams);
CSLDestroy(papszDatum);
return OGRERR_NONE;
not_enough_data:
CSLDestroy(papszProj);
CSLDestroy(papszProjParams);
CSLDestroy(papszDatum);
return OGRERR_NOT_ENOUGH_DATA;
other_error:
CSLDestroy(papszProj);
CSLDestroy(papszProjParams);
CSLDestroy(papszDatum);
return OGRERR_FAILURE;
}