1 : /******************************************************************************
2 : * $Id: ogr_srs_esri.cpp 25575 2013-01-28 20:33:32Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: OGRSpatialReference translation to/from ESRI .prj definitions.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2000, Frank Warmerdam
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_spatialref.h"
31 : #include "ogr_p.h"
32 : #include "cpl_csv.h"
33 : #include "cpl_multiproc.h"
34 :
35 : #include "ogr_srs_esri_names.h"
36 :
37 : CPL_CVSID("$Id: ogr_srs_esri.cpp 25575 2013-01-28 20:33:32Z rouault $");
38 :
39 : void SetNewName( OGRSpatialReference* pOgr, const char* keyName, const char* newName );
40 : int RemapImgWGSProjcsName(OGRSpatialReference* pOgr, const char* pszProjCSName,
41 : const char* pszProgCSName);
42 : int RemapImgUTMNames(OGRSpatialReference* pOgr, const char* pszProjCSName,
43 : const char* pszProgCSName, char **mappingTable);
44 : int RemapNameBasedOnKeyName(OGRSpatialReference* pOgr, const char* pszName,
45 : const char* pszkeyName, char **mappingTable);
46 : int RemapNamesBasedOnTwo(OGRSpatialReference* pOgr, const char* name1, const char* name2,
47 : char **mappingTable, long nTableStepSize,
48 : char** pszkeyNames, long nKeys);
49 : int RemapPValuesBasedOnProjCSAndPName(OGRSpatialReference* pOgr,
50 : const char* pszProgCSName, char **mappingTable);
51 : int RemapPNamesBasedOnProjCSAndPName(OGRSpatialReference* pOgr,
52 : const char* pszProgCSName, char **mappingTable);
53 : int DeleteParamBasedOnPrjName( OGRSpatialReference* pOgr,
54 : const char* pszProjectionName, char **mappingTable);
55 : int AddParamBasedOnPrjName( OGRSpatialReference* pOgr,
56 : const char* pszProjectionName, char **mappingTable);
57 : int RemapGeogCSName(OGRSpatialReference* pOgr, const char *pszGeogCSName);
58 :
59 : static int FindCodeFromDict( const char* pszDictFile, const char* CSName, char* code );
60 :
61 : static const char *apszProjMapping[] = {
62 : "Albers", SRS_PT_ALBERS_CONIC_EQUAL_AREA,
63 : "Cassini", SRS_PT_CASSINI_SOLDNER,
64 : "Equidistant_Cylindrical", SRS_PT_EQUIRECTANGULAR,
65 : "Plate_Carree", SRS_PT_EQUIRECTANGULAR,
66 : "Hotine_Oblique_Mercator_Azimuth_Natural_Origin",
67 : SRS_PT_HOTINE_OBLIQUE_MERCATOR,
68 : "Lambert_Conformal_Conic", SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP,
69 : "Lambert_Conformal_Conic", SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP,
70 : "Van_der_Grinten_I", SRS_PT_VANDERGRINTEN,
71 : SRS_PT_TRANSVERSE_MERCATOR, SRS_PT_TRANSVERSE_MERCATOR,
72 : "Gauss_Kruger", SRS_PT_TRANSVERSE_MERCATOR,
73 : "Mercator", SRS_PT_MERCATOR_1SP,
74 : NULL, NULL };
75 :
76 : static const char *apszAlbersMapping[] = {
77 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_LONGITUDE_OF_CENTER,
78 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_LATITUDE_OF_CENTER,
79 : "Central_Parallel", SRS_PP_LATITUDE_OF_CENTER,
80 : NULL, NULL };
81 :
82 : static const char *apszECMapping[] = {
83 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_LONGITUDE_OF_CENTER,
84 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_LATITUDE_OF_CENTER,
85 : NULL, NULL };
86 :
87 : static const char *apszMercatorMapping[] = {
88 : SRS_PP_STANDARD_PARALLEL_1, SRS_PP_LATITUDE_OF_ORIGIN,
89 : NULL, NULL };
90 :
91 : static const char *apszPolarStereographicMapping[] = {
92 : SRS_PP_STANDARD_PARALLEL_1, SRS_PP_LATITUDE_OF_ORIGIN,
93 : NULL, NULL };
94 :
95 : static const char *apszOrthographicMapping[] = {
96 : "Longitude_Of_Center", SRS_PP_CENTRAL_MERIDIAN,
97 : "Latitude_Of_Center", SRS_PP_LATITUDE_OF_ORIGIN,
98 : NULL, NULL };
99 :
100 : static char **papszDatumMapping = NULL;
101 : static void* hDatumMappingMutex = NULL;
102 :
103 : static const char *apszDefaultDatumMapping[] = {
104 : "6267", "North_American_1927", SRS_DN_NAD27,
105 : "6269", "North_American_1983", SRS_DN_NAD83,
106 : NULL, NULL, NULL };
107 :
108 : static const char *apszSpheroidMapping[] = {
109 : "WGS_84", "WGS_1984",
110 : "WGS_72", "WGS_1972",
111 : "GRS_1967_Modified", "GRS_1967_Truncated",
112 : "Krassowsky_1940", "Krasovsky_1940",
113 : "Everest_1830_1937_Adjustment", "Everest_Adjustment_1937",
114 : NULL, NULL };
115 :
116 : static const char *apszUnitMapping[] = {
117 : "Meter", "meter",
118 : "Meter", "metre",
119 : "Foot", "foot",
120 : "Foot", "feet",
121 : "Foot", "international_feet",
122 : "Foot_US", SRS_UL_US_FOOT,
123 : "Foot_Clarke", "clarke_feet",
124 : "Degree", "degree",
125 : "Degree", "degrees",
126 : "Degree", SRS_UA_DEGREE,
127 : "Radian", SRS_UA_RADIAN,
128 : NULL, NULL };
129 :
130 : /* -------------------------------------------------------------------- */
131 : /* Table relating USGS and ESRI state plane zones. */
132 : /* -------------------------------------------------------------------- */
133 : static const int anUsgsEsriZones[] =
134 : {
135 : 101, 3101,
136 : 102, 3126,
137 : 201, 3151,
138 : 202, 3176,
139 : 203, 3201,
140 : 301, 3226,
141 : 302, 3251,
142 : 401, 3276,
143 : 402, 3301,
144 : 403, 3326,
145 : 404, 3351,
146 : 405, 3376,
147 : 406, 3401,
148 : 407, 3426,
149 : 501, 3451,
150 : 502, 3476,
151 : 503, 3501,
152 : 600, 3526,
153 : 700, 3551,
154 : 901, 3601,
155 : 902, 3626,
156 : 903, 3576,
157 : 1001, 3651,
158 : 1002, 3676,
159 : 1101, 3701,
160 : 1102, 3726,
161 : 1103, 3751,
162 : 1201, 3776,
163 : 1202, 3801,
164 : 1301, 3826,
165 : 1302, 3851,
166 : 1401, 3876,
167 : 1402, 3901,
168 : 1501, 3926,
169 : 1502, 3951,
170 : 1601, 3976,
171 : 1602, 4001,
172 : 1701, 4026,
173 : 1702, 4051,
174 : 1703, 6426,
175 : 1801, 4076,
176 : 1802, 4101,
177 : 1900, 4126,
178 : 2001, 4151,
179 : 2002, 4176,
180 : 2101, 4201,
181 : 2102, 4226,
182 : 2103, 4251,
183 : 2111, 6351,
184 : 2112, 6376,
185 : 2113, 6401,
186 : 2201, 4276,
187 : 2202, 4301,
188 : 2203, 4326,
189 : 2301, 4351,
190 : 2302, 4376,
191 : 2401, 4401,
192 : 2402, 4426,
193 : 2403, 4451,
194 : 2500, 0,
195 : 2501, 4476,
196 : 2502, 4501,
197 : 2503, 4526,
198 : 2600, 0,
199 : 2601, 4551,
200 : 2602, 4576,
201 : 2701, 4601,
202 : 2702, 4626,
203 : 2703, 4651,
204 : 2800, 4676,
205 : 2900, 4701,
206 : 3001, 4726,
207 : 3002, 4751,
208 : 3003, 4776,
209 : 3101, 4801,
210 : 3102, 4826,
211 : 3103, 4851,
212 : 3104, 4876,
213 : 3200, 4901,
214 : 3301, 4926,
215 : 3302, 4951,
216 : 3401, 4976,
217 : 3402, 5001,
218 : 3501, 5026,
219 : 3502, 5051,
220 : 3601, 5076,
221 : 3602, 5101,
222 : 3701, 5126,
223 : 3702, 5151,
224 : 3800, 5176,
225 : 3900, 0,
226 : 3901, 5201,
227 : 3902, 5226,
228 : 4001, 5251,
229 : 4002, 5276,
230 : 4100, 5301,
231 : 4201, 5326,
232 : 4202, 5351,
233 : 4203, 5376,
234 : 4204, 5401,
235 : 4205, 5426,
236 : 4301, 5451,
237 : 4302, 5476,
238 : 4303, 5501,
239 : 4400, 5526,
240 : 4501, 5551,
241 : 4502, 5576,
242 : 4601, 5601,
243 : 4602, 5626,
244 : 4701, 5651,
245 : 4702, 5676,
246 : 4801, 5701,
247 : 4802, 5726,
248 : 4803, 5751,
249 : 4901, 5776,
250 : 4902, 5801,
251 : 4903, 5826,
252 : 4904, 5851,
253 : 5001, 6101,
254 : 5002, 6126,
255 : 5003, 6151,
256 : 5004, 6176,
257 : 5005, 6201,
258 : 5006, 6226,
259 : 5007, 6251,
260 : 5008, 6276,
261 : 5009, 6301,
262 : 5010, 6326,
263 : 5101, 5876,
264 : 5102, 5901,
265 : 5103, 5926,
266 : 5104, 5951,
267 : 5105, 5976,
268 : 5201, 6001,
269 : 5200, 6026,
270 : 5200, 6076,
271 : 5201, 6051,
272 : 5202, 6051,
273 : 5300, 0,
274 : 5400, 0
275 : };
276 :
277 : /* -------------------------------------------------------------------- */
278 : /* Datum Mapping functions and definitions */
279 : /* -------------------------------------------------------------------- */
280 : /* TODO adapt existing code and test */
281 : #define DM_IDX_EPSG_CODE 0
282 : #define DM_IDX_ESRI_NAME 1
283 : #define DM_IDX_EPSG_NAME 2
284 : #define DM_ELT_SIZE 3
285 :
286 : #define DM_GET_EPSG_CODE(map, i) map[(i)*DM_ELT_SIZE + DM_IDX_EPSG_CODE]
287 : #define DM_GET_ESRI_NAME(map, i) map[(i)*DM_ELT_SIZE + DM_IDX_ESRI_NAME]
288 : #define DM_GET_EPSG_NAME(map, i) map[(i)*DM_ELT_SIZE + DM_IDX_EPSG_NAME]
289 :
290 4265 : char *DMGetEPSGCode(int i) { return DM_GET_EPSG_CODE(papszDatumMapping, i); }
291 4415557 : char *DMGetESRIName(int i) { return DM_GET_ESRI_NAME(papszDatumMapping, i); }
292 0 : char *DMGetEPSGName(int i) { return DM_GET_EPSG_NAME(papszDatumMapping, i); }
293 :
294 :
295 : void OGREPSGDatumNameMassage( char ** ppszDatum );
296 :
297 : /************************************************************************/
298 : /* ESRIToUSGSZone() */
299 : /* */
300 : /* Convert ESRI style state plane zones to USGS style state */
301 : /* plane zones. */
302 : /************************************************************************/
303 :
304 0 : static int ESRIToUSGSZone( int nESRIZone )
305 :
306 : {
307 0 : int nPairs = sizeof(anUsgsEsriZones) / (2*sizeof(int));
308 : int i;
309 :
310 0 : for( i = 0; i < nPairs; i++ )
311 : {
312 0 : if( anUsgsEsriZones[i*2+1] == nESRIZone )
313 0 : return anUsgsEsriZones[i*2];
314 : }
315 :
316 0 : return 0;
317 : }
318 :
319 : /************************************************************************/
320 : /* MorphNameToESRI() */
321 : /* */
322 : /* Make name ESRI compatible. Convert spaces and special */
323 : /* characters to underscores and then strip down. */
324 : /************************************************************************/
325 :
326 26954 : static void MorphNameToESRI( char ** ppszName )
327 :
328 : {
329 : int i, j;
330 26954 : char *pszName = *ppszName;
331 :
332 26954 : if (pszName[0] == '\0')
333 0 : return;
334 :
335 : /* -------------------------------------------------------------------- */
336 : /* Translate non-alphanumeric values to underscores. */
337 : /* -------------------------------------------------------------------- */
338 575612 : for( i = 0; pszName[i] != '\0'; i++ )
339 : {
340 2443866 : if( pszName[i] != '+'
341 919828 : && !(pszName[i] >= 'A' && pszName[i] <= 'Z')
342 620873 : && !(pszName[i] >= 'a' && pszName[i] <= 'z')
343 354507 : && !(pszName[i] >= '0' && pszName[i] <= '9') )
344 : {
345 95088 : pszName[i] = '_';
346 : }
347 : }
348 :
349 : /* -------------------------------------------------------------------- */
350 : /* Remove repeated and trailing underscores. */
351 : /* -------------------------------------------------------------------- */
352 548658 : for( i = 1, j = 0; pszName[i] != '\0'; i++ )
353 : {
354 521704 : if( pszName[j] == '_' && pszName[i] == '_' )
355 19264 : continue;
356 :
357 502440 : pszName[++j] = pszName[i];
358 : }
359 26954 : if( pszName[j] == '_' )
360 2193 : pszName[j] = '\0';
361 : else
362 24761 : pszName[j+1] = '\0';
363 : }
364 :
365 : /************************************************************************/
366 : /* CleanESRIDatumMappingTable() */
367 : /************************************************************************/
368 :
369 : CPL_C_START
370 1057 : void CleanupESRIDatumMappingTable()
371 :
372 : {
373 1057 : if( papszDatumMapping == NULL )
374 962 : return;
375 :
376 95 : if( papszDatumMapping != (char **) apszDefaultDatumMapping )
377 : {
378 95 : CSLDestroy( papszDatumMapping );
379 95 : papszDatumMapping = NULL;
380 : }
381 :
382 95 : CPLDestroyMutex(hDatumMappingMutex);
383 : }
384 : CPL_C_END
385 :
386 : /************************************************************************/
387 : /* InitDatumMappingTable() */
388 : /************************************************************************/
389 :
390 45022 : static void InitDatumMappingTable()
391 :
392 : {
393 45022 : CPLMutexHolderD(&hDatumMappingMutex);
394 45022 : if( papszDatumMapping != NULL )
395 : return;
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Try to open the datum.csv file. */
399 : /* -------------------------------------------------------------------- */
400 95 : const char *pszFilename = CSVFilename("gdal_datum.csv");
401 95 : FILE * fp = VSIFOpen( pszFilename, "rb" );
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Use simple default set if we can't find the file. */
405 : /* -------------------------------------------------------------------- */
406 95 : if( fp == NULL )
407 : {
408 0 : papszDatumMapping = (char **)apszDefaultDatumMapping;
409 : return;
410 : }
411 :
412 : /* -------------------------------------------------------------------- */
413 : /* Figure out what fields we are interested in. */
414 : /* -------------------------------------------------------------------- */
415 95 : char **papszFieldNames = CSVReadParseLine( fp );
416 95 : int nDatumCodeField = CSLFindString( papszFieldNames, "DATUM_CODE" );
417 95 : int nEPSGNameField = CSLFindString( papszFieldNames, "DATUM_NAME" );
418 95 : int nESRINameField = CSLFindString( papszFieldNames, "ESRI_DATUM_NAME" );
419 :
420 95 : CSLDestroy( papszFieldNames );
421 :
422 95 : if( nDatumCodeField == -1 || nEPSGNameField == -1 || nESRINameField == -1 )
423 : {
424 : CPLError( CE_Failure, CPLE_AppDefined,
425 0 : "Failed to find required field in gdal_datum.csv in InitDatumMappingTable(), using default table setup." );
426 :
427 0 : papszDatumMapping = (char **)apszDefaultDatumMapping;
428 0 : VSIFClose( fp );
429 : return;
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Read each line, adding a detail line for each. */
434 : /* -------------------------------------------------------------------- */
435 95 : int nMappingCount = 0;
436 95 : const int nMaxDatumMappings = 1000;
437 : char **papszFields;
438 95 : papszDatumMapping = (char **)CPLCalloc(sizeof(char*),nMaxDatumMappings*3);
439 :
440 59945 : for( papszFields = CSVReadParseLine( fp );
441 : papszFields != NULL;
442 : papszFields = CSVReadParseLine( fp ) )
443 : {
444 59850 : int nFieldCount = CSLCount(papszFields);
445 :
446 59850 : CPLAssert( nMappingCount+1 < nMaxDatumMappings );
447 :
448 59850 : if( MAX(nEPSGNameField,MAX(nDatumCodeField,nESRINameField))
449 : < nFieldCount
450 : && nMaxDatumMappings > nMappingCount+1 )
451 : {
452 59850 : papszDatumMapping[nMappingCount*3+0] =
453 59850 : CPLStrdup( papszFields[nDatumCodeField] );
454 59850 : papszDatumMapping[nMappingCount*3+1] =
455 59850 : CPLStrdup( papszFields[nESRINameField] );
456 59850 : papszDatumMapping[nMappingCount*3+2] =
457 59850 : CPLStrdup( papszFields[nEPSGNameField] );
458 59850 : OGREPSGDatumNameMassage( &(papszDatumMapping[nMappingCount*3+2]) );
459 :
460 59850 : nMappingCount++;
461 : }
462 59850 : CSLDestroy( papszFields );
463 : }
464 :
465 95 : VSIFClose( fp );
466 :
467 95 : papszDatumMapping[nMappingCount*3+0] = NULL;
468 95 : papszDatumMapping[nMappingCount*3+1] = NULL;
469 95 : papszDatumMapping[nMappingCount*3+2] = NULL;
470 : }
471 :
472 :
473 : /************************************************************************/
474 : /* OSRImportFromESRI() */
475 : /************************************************************************/
476 :
477 : /**
478 : * \brief Import coordinate system from ESRI .prj format(s).
479 : *
480 : * This function is the same as the C++ method OGRSpatialReference::importFromESRI()
481 : */
482 5 : OGRErr OSRImportFromESRI( OGRSpatialReferenceH hSRS, char **papszPrj )
483 :
484 : {
485 5 : VALIDATE_POINTER1( hSRS, "OSRImportFromESRI", CE_Failure );
486 :
487 5 : return ((OGRSpatialReference *) hSRS)->importFromESRI( papszPrj );
488 : }
489 :
490 : /************************************************************************/
491 : /* OSR_GDV() */
492 : /* */
493 : /* Fetch a particular parameter out of the parameter list, or */
494 : /* the indicated default if it isn't available. This is a */
495 : /* helper function for importFromESRI(). */
496 : /************************************************************************/
497 :
498 67 : static double OSR_GDV( char **papszNV, const char * pszField,
499 : double dfDefaultValue )
500 :
501 : {
502 : int iLine;
503 :
504 67 : if( papszNV == NULL || papszNV[0] == NULL )
505 0 : return dfDefaultValue;
506 :
507 67 : if( EQUALN(pszField,"PARAM_",6) )
508 : {
509 : int nOffset;
510 :
511 493 : for( iLine = 0;
512 464 : papszNV[iLine] != NULL && !EQUALN(papszNV[iLine],"Paramet",7);
513 : iLine++ ) {}
514 :
515 256 : for( nOffset=atoi(pszField+6);
516 128 : papszNV[iLine] != NULL && nOffset > 0;
517 : iLine++ )
518 : {
519 99 : if( strlen(papszNV[iLine]) > 0 )
520 99 : nOffset--;
521 : }
522 :
523 58 : while( papszNV[iLine] != NULL && strlen(papszNV[iLine]) == 0 )
524 0 : iLine++;
525 :
526 29 : if( papszNV[iLine] != NULL )
527 : {
528 29 : char **papszTokens, *pszLine = papszNV[iLine];
529 : double dfValue;
530 :
531 : int i;
532 :
533 : // Trim comments.
534 2060 : for( i=0; pszLine[i] != '\0'; i++ )
535 : {
536 2031 : if( pszLine[i] == '/' && pszLine[i+1] == '*' )
537 29 : pszLine[i] = '\0';
538 : }
539 :
540 29 : papszTokens = CSLTokenizeString(papszNV[iLine]);
541 29 : if( CSLCount(papszTokens) == 3 )
542 : {
543 : /* http://agdcftp1.wr.usgs.gov/pub/projects/lcc/akcan_lcc/akcan.tar.gz contains */
544 : /* weird values for the second. Ignore it and the result looks correct */
545 18 : double dfSecond = atof(papszTokens[2]);
546 18 : if (dfSecond < 0.0 || dfSecond >= 60.0)
547 0 : dfSecond = 0.0;
548 :
549 36 : dfValue = ABS(atof(papszTokens[0]))
550 18 : + atof(papszTokens[1]) / 60.0
551 54 : + dfSecond / 3600.0;
552 :
553 18 : if( atof(papszTokens[0]) < 0.0 )
554 5 : dfValue *= -1;
555 : }
556 11 : else if( CSLCount(papszTokens) > 0 )
557 11 : dfValue = atof(papszTokens[0]);
558 : else
559 0 : dfValue = dfDefaultValue;
560 :
561 29 : CSLDestroy( papszTokens );
562 :
563 29 : return dfValue;
564 : }
565 : else
566 0 : return dfDefaultValue;
567 : }
568 : else
569 : {
570 424 : for( iLine = 0;
571 195 : papszNV[iLine] != NULL &&
572 191 : !EQUALN(papszNV[iLine],pszField,strlen(pszField));
573 : iLine++ ) {}
574 :
575 38 : if( papszNV[iLine] == NULL )
576 4 : return dfDefaultValue;
577 : else
578 34 : return atof( papszNV[iLine] + strlen(pszField) );
579 : }
580 : }
581 :
582 : /************************************************************************/
583 : /* OSR_GDS() */
584 : /************************************************************************/
585 :
586 60 : static CPLString OSR_GDS( char **papszNV, const char * pszField,
587 : const char *pszDefaultValue )
588 :
589 : {
590 : int iLine;
591 :
592 60 : if( papszNV == NULL || papszNV[0] == NULL )
593 0 : return pszDefaultValue;
594 :
595 507 : for( iLine = 0;
596 224 : papszNV[iLine] != NULL &&
597 223 : !EQUALN(papszNV[iLine],pszField,strlen(pszField));
598 : iLine++ ) {}
599 :
600 60 : if( papszNV[iLine] == NULL )
601 1 : return pszDefaultValue;
602 : else
603 : {
604 59 : CPLString osResult;
605 : char **papszTokens;
606 :
607 59 : papszTokens = CSLTokenizeString(papszNV[iLine]);
608 :
609 59 : if( CSLCount(papszTokens) > 1 )
610 59 : osResult = papszTokens[1];
611 : else
612 0 : osResult = pszDefaultValue;
613 :
614 59 : CSLDestroy( papszTokens );
615 59 : return osResult;
616 : }
617 : }
618 :
619 : /************************************************************************/
620 : /* importFromESRI() */
621 : /************************************************************************/
622 :
623 : /**
624 : * \brief Import coordinate system from ESRI .prj format(s).
625 : *
626 : * This function will read the text loaded from an ESRI .prj file, and
627 : * translate it into an OGRSpatialReference definition. This should support
628 : * many (but by no means all) old style (Arc/Info 7.x) .prj files, as well
629 : * as the newer pseudo-OGC WKT .prj files. Note that new style .prj files
630 : * are in OGC WKT format, but require some manipulation to correct datum
631 : * names, and units on some projection parameters. This is addressed within
632 : * importFromESRI() by an automatical call to morphFromESRI().
633 : *
634 : * Currently only GEOGRAPHIC, UTM, STATEPLANE, GREATBRITIAN_GRID, ALBERS,
635 : * EQUIDISTANT_CONIC, TRANSVERSE (mercator), POLAR, MERCATOR and POLYCONIC
636 : * projections are supported from old style files.
637 : *
638 : * At this time there is no equivelent exportToESRI() method. Writing old
639 : * style .prj files is not supported by OGRSpatialReference. However the
640 : * morphToESRI() and exportToWkt() methods can be used to generate output
641 : * suitable to write to new style (Arc 8) .prj files.
642 : *
643 : * This function is the equilvelent of the C function OSRImportFromESRI().
644 : *
645 : * @param papszPrj NULL terminated list of strings containing the definition.
646 : *
647 : * @return OGRERR_NONE on success or an error code in case of failure.
648 : */
649 :
650 459 : OGRErr OGRSpatialReference::importFromESRI( char **papszPrj )
651 :
652 : {
653 459 : if( papszPrj == NULL || papszPrj[0] == NULL )
654 15 : return OGRERR_CORRUPT_DATA;
655 :
656 : /* -------------------------------------------------------------------- */
657 : /* ArcGIS and related products now use a varient of Well Known */
658 : /* Text. Try to recognise this and ingest it. WKT is usually */
659 : /* all on one line, but we will accept multi-line formats and */
660 : /* concatenate. */
661 : /* -------------------------------------------------------------------- */
662 735 : if( EQUALN(papszPrj[0],"GEOGCS",6)
663 270 : || EQUALN(papszPrj[0],"PROJCS",6)
664 21 : || EQUALN(papszPrj[0],"LOCAL_CS",8) )
665 : {
666 : char *pszWKT, *pszWKT2;
667 : OGRErr eErr;
668 : int i;
669 :
670 423 : pszWKT = CPLStrdup(papszPrj[0]);
671 423 : for( i = 1; papszPrj[i] != NULL; i++ )
672 : {
673 : pszWKT = (char *)
674 0 : CPLRealloc(pszWKT,strlen(pszWKT)+strlen(papszPrj[i])+1);
675 0 : strcat( pszWKT, papszPrj[i] );
676 : }
677 423 : pszWKT2 = pszWKT;
678 423 : eErr = importFromWkt( &pszWKT2 );
679 423 : CPLFree( pszWKT );
680 :
681 423 : if( eErr == OGRERR_NONE )
682 423 : eErr = morphFromESRI();
683 423 : return eErr;
684 : }
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Operate on the basis of the projection name. */
688 : /* -------------------------------------------------------------------- */
689 21 : CPLString osProj = OSR_GDS( papszPrj, "Projection", "" );
690 :
691 21 : if( EQUAL(osProj,"") )
692 : {
693 1 : CPLDebug( "OGR_ESRI", "Can't find Projection\n" );
694 1 : return OGRERR_CORRUPT_DATA;
695 : }
696 :
697 20 : else if( EQUAL(osProj,"GEOGRAPHIC") )
698 : {
699 : }
700 :
701 19 : else if( EQUAL(osProj,"utm") )
702 : {
703 10 : if( (int) OSR_GDV( papszPrj, "zone", 0.0 ) != 0 )
704 : {
705 10 : double dfYShift = OSR_GDV( papszPrj, "Yshift", 0.0 );
706 :
707 : SetUTM( (int) OSR_GDV( papszPrj, "zone", 0.0 ),
708 10 : dfYShift == 0.0 );
709 : }
710 : else
711 : {
712 : double dfCentralMeridian, dfRefLat;
713 : int nZone;
714 :
715 0 : dfCentralMeridian = OSR_GDV( papszPrj, "PARAM_1", 0.0 );
716 0 : dfRefLat = OSR_GDV( papszPrj, "PARAM_2", 0.0 );
717 :
718 0 : nZone = (int) ((dfCentralMeridian+183) / 6.0 + 0.0000001);
719 0 : SetUTM( nZone, dfRefLat >= 0.0 );
720 : }
721 : }
722 :
723 9 : else if( EQUAL(osProj,"STATEPLANE") )
724 : {
725 4 : int nZone = (int) OSR_GDV( papszPrj, "zone", 0.0 );
726 4 : if( nZone != 0 )
727 0 : nZone = ESRIToUSGSZone( nZone );
728 : else
729 4 : nZone = (int) OSR_GDV( papszPrj, "fipszone", 0.0 );
730 :
731 4 : if( nZone != 0 )
732 : {
733 4 : if( EQUAL(OSR_GDS( papszPrj, "Datum", "NAD83"),"NAD27") )
734 0 : SetStatePlane( nZone, FALSE );
735 : else
736 4 : SetStatePlane( nZone, TRUE );
737 : }
738 : }
739 :
740 5 : else if( EQUAL(osProj,"GREATBRITIAN_GRID")
741 : || EQUAL(osProj,"GREATBRITAIN_GRID") )
742 : {
743 : const char *pszWkt =
744 0 : "PROJCS[\"OSGB 1936 / British National Grid\",GEOGCS[\"OSGB 1936\",DATUM[\"OSGB_1936\",SPHEROID[\"Airy 1830\",6377563.396,299.3249646]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",49],PARAMETER[\"central_meridian\",-2],PARAMETER[\"scale_factor\",0.999601272],PARAMETER[\"false_easting\",400000],PARAMETER[\"false_northing\",-100000],UNIT[\"metre\",1]]";
745 :
746 0 : importFromWkt( (char **) &pszWkt );
747 : }
748 :
749 5 : else if( EQUAL(osProj,"ALBERS") )
750 : {
751 : SetACEA( OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
752 : OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
753 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ),
754 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
755 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ),
756 4 : OSR_GDV( papszPrj, "PARAM_6", 0.0 ) );
757 : }
758 :
759 1 : else if( EQUAL(osProj,"LAMBERT") )
760 : {
761 : SetLCC( OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
762 : OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
763 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ),
764 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
765 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ),
766 0 : OSR_GDV( papszPrj, "PARAM_6", 0.0 ) );
767 : }
768 :
769 1 : else if( EQUAL(osProj,"LAMBERT_AZIMUTHAL") )
770 : {
771 : SetLAEA( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
772 : OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
773 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
774 0 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ) );
775 : }
776 :
777 1 : else if( EQUAL(osProj,"EQUIDISTANT_CONIC") )
778 : {
779 0 : int nStdPCount = (int) OSR_GDV( papszPrj, "PARAM_1", 0.0 );
780 :
781 0 : if( nStdPCount == 1 )
782 : {
783 : SetEC( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
784 : OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
785 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ),
786 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
787 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ),
788 0 : OSR_GDV( papszPrj, "PARAM_6", 0.0 ) );
789 : }
790 : else
791 : {
792 : SetEC( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
793 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
794 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ),
795 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ),
796 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ),
797 0 : OSR_GDV( papszPrj, "PARAM_7", 0.0 ) );
798 : }
799 : }
800 :
801 1 : else if( EQUAL(osProj,"TRANSVERSE") )
802 : {
803 : SetTM( OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
804 : OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
805 : OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
806 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ),
807 1 : OSR_GDV( papszPrj, "PARAM_5", 0.0 ) );
808 : }
809 :
810 0 : else if( EQUAL(osProj,"POLAR") )
811 : {
812 : SetPS( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
813 : OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
814 : 1.0,
815 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
816 0 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ) );
817 : }
818 :
819 0 : else if( EQUAL(osProj,"MERCATOR") )
820 : {
821 : SetMercator( OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
822 : OSR_GDV( papszPrj, "PARAM_0", 0.0 ),
823 : 1.0,
824 : OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
825 0 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ) );
826 : }
827 :
828 0 : else if( EQUAL(osProj,"POLYCONIC") )
829 : {
830 : SetPolyconic( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
831 : OSR_GDV( papszPrj, "PARAM_1", 0.0 ),
832 : OSR_GDV( papszPrj, "PARAM_3", 0.0 ),
833 0 : OSR_GDV( papszPrj, "PARAM_4", 0.0 ) );
834 : }
835 :
836 : else
837 : {
838 0 : CPLDebug( "OGR_ESRI", "Unsupported projection: %s", osProj.c_str() );
839 0 : SetLocalCS( osProj );
840 : }
841 :
842 : /* -------------------------------------------------------------------- */
843 : /* Try to translate the datum/spheroid. */
844 : /* -------------------------------------------------------------------- */
845 20 : if( !IsLocal() && GetAttrNode( "GEOGCS" ) == NULL )
846 : {
847 16 : CPLString osDatum;
848 :
849 16 : osDatum = OSR_GDS( papszPrj, "Datum", "");
850 :
851 16 : if( EQUAL(osDatum,"NAD27") || EQUAL(osDatum,"NAD83")
852 : || EQUAL(osDatum,"WGS84") || EQUAL(osDatum,"WGS72") )
853 : {
854 11 : SetWellKnownGeogCS( osDatum );
855 : }
856 5 : else if( EQUAL( osDatum, "EUR" )
857 : || EQUAL( osDatum, "ED50" ) )
858 : {
859 0 : SetWellKnownGeogCS( "EPSG:4230" );
860 : }
861 5 : else if( EQUAL( osDatum, "GDA94" ) )
862 : {
863 5 : SetWellKnownGeogCS( "EPSG:4283" );
864 : }
865 : else
866 : {
867 0 : CPLString osSpheroid;
868 :
869 0 : osSpheroid = OSR_GDS( papszPrj, "Spheroid", "");
870 :
871 0 : if( EQUAL(osSpheroid,"INT1909")
872 : || EQUAL(osSpheroid,"INTERNATIONAL1909") )
873 : {
874 0 : OGRSpatialReference oGCS;
875 0 : oGCS.importFromEPSG( 4022 );
876 0 : CopyGeogCSFrom( &oGCS );
877 : }
878 0 : else if( EQUAL(osSpheroid,"AIRY") )
879 : {
880 0 : OGRSpatialReference oGCS;
881 0 : oGCS.importFromEPSG( 4001 );
882 0 : CopyGeogCSFrom( &oGCS );
883 : }
884 0 : else if( EQUAL(osSpheroid,"CLARKE1866") )
885 : {
886 0 : OGRSpatialReference oGCS;
887 0 : oGCS.importFromEPSG( 4008 );
888 0 : CopyGeogCSFrom( &oGCS );
889 : }
890 0 : else if( EQUAL(osSpheroid,"GRS80") )
891 : {
892 0 : OGRSpatialReference oGCS;
893 0 : oGCS.importFromEPSG( 4019 );
894 0 : CopyGeogCSFrom( &oGCS );
895 : }
896 0 : else if( EQUAL(osSpheroid,"KRASOVSKY")
897 : || EQUAL(osSpheroid,"KRASSOVSKY")
898 : || EQUAL(osSpheroid,"KRASSOWSKY") )
899 : {
900 0 : OGRSpatialReference oGCS;
901 0 : oGCS.importFromEPSG( 4024 );
902 0 : CopyGeogCSFrom( &oGCS );
903 : }
904 0 : else if( EQUAL(osSpheroid,"Bessel") )
905 : {
906 0 : OGRSpatialReference oGCS;
907 0 : oGCS.importFromEPSG( 4004 );
908 0 : CopyGeogCSFrom( &oGCS );
909 : }
910 : else
911 : {
912 : // If we don't know, default to WGS84 so there is something there.
913 0 : SetWellKnownGeogCS( "WGS84" );
914 0 : }
915 16 : }
916 : }
917 :
918 : /* -------------------------------------------------------------------- */
919 : /* Linear units translation */
920 : /* -------------------------------------------------------------------- */
921 20 : if( IsLocal() || IsProjected() )
922 : {
923 19 : CPLString osValue;
924 19 : double dfOldUnits = GetLinearUnits();
925 :
926 19 : osValue = OSR_GDS( papszPrj, "Units", "" );
927 19 : if( EQUAL(osValue, "" ) )
928 0 : SetLinearUnitsAndUpdateParameters( SRS_UL_METER, 1.0 );
929 19 : else if( EQUAL(osValue,"FEET") )
930 2 : SetLinearUnitsAndUpdateParameters( SRS_UL_US_FOOT, atof(SRS_UL_US_FOOT_CONV) );
931 17 : else if( atof(osValue) != 0.0 )
932 : SetLinearUnitsAndUpdateParameters( "user-defined",
933 1 : 1.0 / atof(osValue) );
934 : else
935 16 : SetLinearUnitsAndUpdateParameters( osValue, 1.0 );
936 :
937 : // If we have reset the linear units we should clear any authority
938 : // nodes on the PROJCS. This especially applies to state plane
939 : // per bug 1697
940 19 : double dfNewUnits = GetLinearUnits();
941 19 : if( dfOldUnits != 0.0
942 : && (dfNewUnits / dfOldUnits < 0.9999999
943 : || dfNewUnits / dfOldUnits > 1.0000001) )
944 : {
945 3 : if( GetRoot()->FindChild( "AUTHORITY" ) != -1 )
946 3 : GetRoot()->DestroyChild(GetRoot()->FindChild( "AUTHORITY" ));
947 19 : }
948 : }
949 :
950 20 : return OGRERR_NONE;
951 : }
952 :
953 : /************************************************************************/
954 : /* morphToESRI() */
955 : /************************************************************************/
956 : /**
957 : * \brief Convert in place to ESRI WKT format.
958 : *
959 : * The value nodes of this coordinate system are modified in various manners
960 : * more closely map onto the ESRI concept of WKT format. This includes
961 : * renaming a variety of projections and arguments, and stripping out
962 : * nodes note recognised by ESRI (like AUTHORITY and AXIS).
963 : *
964 : * This does the same as the C function OSRMorphToESRI().
965 : *
966 : * @return OGRERR_NONE unless something goes badly wrong.
967 : */
968 :
969 14821 : OGRErr OGRSpatialReference::morphToESRI()
970 :
971 : {
972 : OGRErr eErr;
973 :
974 14821 : CPLLocaleC localeC;
975 : /* -------------------------------------------------------------------- */
976 : /* Fixup ordering, missing linear units, etc. */
977 : /* -------------------------------------------------------------------- */
978 14821 : eErr = Fixup();
979 14821 : if( eErr != OGRERR_NONE )
980 0 : return eErr;
981 :
982 : /* -------------------------------------------------------------------- */
983 : /* Strip all CT parameters (AXIS, AUTHORITY, TOWGS84, etc). */
984 : /* -------------------------------------------------------------------- */
985 14821 : eErr = StripCTParms();
986 14821 : if( eErr != OGRERR_NONE )
987 0 : return eErr;
988 :
989 14821 : if( GetRoot() == NULL )
990 1 : return OGRERR_NONE;
991 :
992 : /* -------------------------------------------------------------------- */
993 : /* There is a special case for Hotine Oblique Mercator to split */
994 : /* out the case with an angle to rectified grid. Bug 423 */
995 : /* -------------------------------------------------------------------- */
996 14820 : const char *pszProjection = GetAttrValue("PROJECTION");
997 :
998 14820 : if( pszProjection != NULL
999 : && EQUAL(pszProjection,SRS_PT_HOTINE_OBLIQUE_MERCATOR)
1000 : && fabs(GetProjParm(SRS_PP_AZIMUTH, 0.0 )-90) < 0.0001
1001 : && fabs(GetProjParm(SRS_PP_RECTIFIED_GRID_ANGLE, 0.0 )-90) < 0.0001 )
1002 : {
1003 : SetNode( "PROJCS|PROJECTION",
1004 0 : "Hotine_Oblique_Mercator_Azimuth_Center" );
1005 :
1006 : /* ideally we should strip out of the rectified_grid_angle */
1007 : // strip off rectified_grid_angle -- I hope it is 90!
1008 0 : OGR_SRSNode *poPROJCS = GetAttrNode( "PROJCS" );
1009 0 : int iRGAChild = FindProjParm( "rectified_grid_angle", poPROJCS );
1010 0 : if( iRGAChild != -1 )
1011 0 : poPROJCS->DestroyChild( iRGAChild);
1012 :
1013 0 : pszProjection = GetAttrValue("PROJECTION");
1014 : }
1015 :
1016 : /* -------------------------------------------------------------------- */
1017 : /* Polar_Stereographic maps to ESRI codes */
1018 : /* Stereographic_South_Pole or Stereographic_North_Pole based */
1019 : /* on latitude. */
1020 : /* -------------------------------------------------------------------- */
1021 14820 : if( pszProjection != NULL
1022 : && ( EQUAL(pszProjection,SRS_PT_POLAR_STEREOGRAPHIC) ))
1023 : {
1024 80 : if( GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0 ) < 0.0 )
1025 : {
1026 : SetNode( "PROJCS|PROJECTION",
1027 60 : "Stereographic_South_Pole" );
1028 60 : pszProjection = GetAttrValue("PROJECTION");
1029 : }
1030 : else
1031 : {
1032 : SetNode( "PROJCS|PROJECTION",
1033 20 : "Stereographic_North_Pole" );
1034 20 : pszProjection = GetAttrValue("PROJECTION");
1035 : }
1036 : }
1037 :
1038 : /* -------------------------------------------------------------------- */
1039 : /* OBLIQUE_STEREOGRAPHIC maps to ESRI Double_Stereographic */
1040 : /* -------------------------------------------------------------------- */
1041 14820 : if( pszProjection != NULL
1042 : && ( EQUAL(pszProjection,SRS_PT_OBLIQUE_STEREOGRAPHIC) ))
1043 : {
1044 60 : SetNode( "PROJCS|PROJECTION", "Double_Stereographic" );
1045 : }
1046 :
1047 : /* -------------------------------------------------------------------- */
1048 : /* Translate PROJECTION keywords that are misnamed. */
1049 : /* -------------------------------------------------------------------- */
1050 : GetRoot()->applyRemapper( "PROJECTION",
1051 : (char **)apszProjMapping+1,
1052 14820 : (char **)apszProjMapping, 2 );
1053 14820 : pszProjection = GetAttrValue("PROJECTION");
1054 :
1055 : /* -------------------------------------------------------------------- */
1056 : /* Translate DATUM keywords that are misnamed. */
1057 : /* -------------------------------------------------------------------- */
1058 14820 : InitDatumMappingTable();
1059 :
1060 : GetRoot()->applyRemapper( "DATUM",
1061 14820 : papszDatumMapping+2, papszDatumMapping+1, 3 );
1062 :
1063 14820 : const char *pszProjCSName = NULL;
1064 14820 : const char *pszGcsName = NULL;
1065 14820 : OGR_SRSNode *poProjCS = NULL;
1066 14820 : OGR_SRSNode *poProjCSNodeChild = NULL;
1067 :
1068 : /* -------------------------------------------------------------------- */
1069 : /* Very specific handling for some well known geographic */
1070 : /* coordinate systems. */
1071 : /* -------------------------------------------------------------------- */
1072 14820 : OGR_SRSNode *poGeogCS = GetAttrNode( "GEOGCS" );
1073 14820 : if( poGeogCS != NULL )
1074 : {
1075 14820 : const char *pszGeogCSName = poGeogCS->GetChild(0)->GetValue();
1076 14820 : const char *pszAuthName = GetAuthorityName("GEOGCS");
1077 14820 : const char *pszUTMPrefix = NULL;
1078 14820 : int nGCSCode = -1;
1079 :
1080 14820 : if( pszAuthName != NULL && EQUAL(pszAuthName,"EPSG") )
1081 0 : nGCSCode = atoi(GetAuthorityCode("GEOGCS"));
1082 :
1083 15507 : if( nGCSCode == 4326
1084 : || EQUAL(pszGeogCSName,"WGS84")
1085 : || EQUAL(pszGeogCSName,"WGS 84") )
1086 : {
1087 687 : poGeogCS->GetChild(0)->SetValue( "GCS_WGS_1984" );
1088 687 : pszUTMPrefix = "WGS_1984";
1089 : }
1090 14611 : else if( nGCSCode == 4267
1091 : || EQUAL(pszGeogCSName,"NAD27")
1092 : || EQUAL(pszGeogCSName,"NAD 27") )
1093 : {
1094 478 : poGeogCS->GetChild(0)->SetValue( "GCS_North_American_1927" );
1095 478 : pszUTMPrefix = "NAD_1927";
1096 : }
1097 14344 : else if( nGCSCode == 4269
1098 : || EQUAL(pszGeogCSName,"NAD83")
1099 : || EQUAL(pszGeogCSName,"NAD 83") )
1100 : {
1101 689 : poGeogCS->GetChild(0)->SetValue( "GCS_North_American_1983" );
1102 689 : pszUTMPrefix = "NAD_1983";
1103 : }
1104 13051 : else if( nGCSCode == 4167
1105 : || EQUAL(pszGeogCSName,"NZGD2000")
1106 : || EQUAL(pszGeogCSName,"NZGD 2000") )
1107 : {
1108 85 : poGeogCS->GetChild(0)->SetValue( "GCS_NZGD_2000" );
1109 85 : pszUTMPrefix = "NZGD_2000";
1110 : }
1111 12881 : else if( nGCSCode == 4272
1112 : || EQUAL(pszGeogCSName,"NZGD49")
1113 : || EQUAL(pszGeogCSName,"NZGD 49") )
1114 : {
1115 72 : poGeogCS->GetChild(0)->SetValue( "GCS_New_Zealand_1949" );
1116 72 : pszUTMPrefix = "NZGD_1949";
1117 : }
1118 :
1119 : /* -------------------------------------------------------------------- */
1120 : /* Force Unnamed to Unknown for most common locations. */
1121 : /* -------------------------------------------------------------------- */
1122 : static const char *apszUnknownMapping[] = {
1123 : "Unknown", "Unnamed",
1124 : NULL, NULL
1125 : };
1126 :
1127 : GetRoot()->applyRemapper( "PROJCS",
1128 : (char **)apszUnknownMapping+1,
1129 14820 : (char **)apszUnknownMapping+0, 2 );
1130 : GetRoot()->applyRemapper( "GEOGCS",
1131 : (char **)apszUnknownMapping+1,
1132 14820 : (char **)apszUnknownMapping+0, 2 );
1133 : GetRoot()->applyRemapper( "DATUM",
1134 : (char **)apszUnknownMapping+1,
1135 14820 : (char **)apszUnknownMapping+0, 2 );
1136 : GetRoot()->applyRemapper( "SPHEROID",
1137 : (char **)apszUnknownMapping+1,
1138 14820 : (char **)apszUnknownMapping+0, 2 );
1139 : GetRoot()->applyRemapper( "PRIMEM",
1140 : (char **)apszUnknownMapping+1,
1141 14820 : (char **)apszUnknownMapping+0, 2 );
1142 :
1143 : /* -------------------------------------------------------------------- */
1144 : /* If the PROJCS name is unset, use the PROJECTION name in */
1145 : /* place of unknown, or unnamed. At the request of Peng Gao. */
1146 : /* -------------------------------------------------------------------- */
1147 14820 : if( (poProjCS = GetAttrNode( "PROJCS" )) != NULL )
1148 12134 : poProjCSNodeChild = poProjCS->GetChild(0);
1149 :
1150 14820 : if( poProjCSNodeChild )
1151 : {
1152 12134 : pszProjCSName = poProjCSNodeChild->GetValue();
1153 12134 : char *pszNewValue = CPLStrdup(pszProjCSName);
1154 12134 : MorphNameToESRI( &pszNewValue );
1155 12134 : poProjCSNodeChild->SetValue( pszNewValue );
1156 12134 : CPLFree( pszNewValue );
1157 12134 : pszProjCSName = poProjCSNodeChild->GetValue();
1158 : }
1159 :
1160 14820 : if( pszProjCSName != NULL
1161 : && ( EQUAL(pszProjCSName,"unnamed")
1162 : || EQUAL(pszProjCSName,"unknown")
1163 : || EQUAL(pszProjCSName,"") ) )
1164 : {
1165 18 : if( GetAttrValue( "PROJECTION", 0 ) != NULL )
1166 : {
1167 18 : pszProjCSName = GetAttrValue( "PROJECTION", 0 );
1168 18 : poProjCSNodeChild->SetValue( pszProjCSName );
1169 : }
1170 : }
1171 :
1172 : /* -------------------------------------------------------------------- */
1173 : /* Prepare very specific PROJCS names for UTM coordinate */
1174 : /* systems. */
1175 : /* -------------------------------------------------------------------- */
1176 14820 : int bNorth = 0;
1177 14820 : int nZone = 0;
1178 :
1179 : /* get zone from name first */
1180 14820 : if( pszProjCSName && EQUALN(pszProjCSName, "UTM Zone ", 9) )
1181 : {
1182 0 : nZone = atoi(pszProjCSName+9);
1183 0 : if( strstr(pszProjCSName, "North") )
1184 0 : bNorth = 1;
1185 : }
1186 :
1187 : /* if can not get from the name, from the parameters */
1188 14820 : if( nZone <= 0 )
1189 14820 : nZone = GetUTMZone( &bNorth );
1190 :
1191 14820 : if( nZone > 0 && pszUTMPrefix )
1192 : {
1193 : char szUTMName[128];
1194 430 : if( bNorth )
1195 295 : sprintf( szUTMName, "%s_UTM_Zone_%dN", pszUTMPrefix, nZone );
1196 : else
1197 135 : sprintf( szUTMName, "%s_UTM_Zone_%dS", pszUTMPrefix, nZone );
1198 :
1199 430 : if( poProjCSNodeChild )
1200 430 : poProjCSNodeChild->SetValue( szUTMName );
1201 : }
1202 : }
1203 :
1204 : /* -------------------------------------------------------------------- */
1205 : /* Translate UNIT keywords that are misnamed, or even the wrong */
1206 : /* case. */
1207 : /* -------------------------------------------------------------------- */
1208 : GetRoot()->applyRemapper( "UNIT",
1209 : (char **)apszUnitMapping+1,
1210 14820 : (char **)apszUnitMapping, 2 );
1211 :
1212 : /* -------------------------------------------------------------------- */
1213 : /* reset constants for decimal degrees to the exact string ESRI */
1214 : /* expects when encountered to ensure a matchup. */
1215 : /* -------------------------------------------------------------------- */
1216 14820 : OGR_SRSNode *poUnit = GetAttrNode( "GEOGCS|UNIT" );
1217 :
1218 14820 : if( poUnit != NULL && poUnit->GetChildCount() >= 2
1219 : && ABS(GetAngularUnits()-0.0174532925199433) < 0.00000000001 )
1220 : {
1221 14709 : poUnit->GetChild(0)->SetValue("Degree");
1222 14709 : poUnit->GetChild(1)->SetValue("0.017453292519943295");
1223 : }
1224 :
1225 : /* -------------------------------------------------------------------- */
1226 : /* Make sure we reproduce US Feet exactly too. */
1227 : /* -------------------------------------------------------------------- */
1228 14820 : poUnit = GetAttrNode( "PROJCS|UNIT" );
1229 :
1230 14820 : if( poUnit != NULL && poUnit->GetChildCount() >= 2
1231 : && ABS(GetLinearUnits()- 0.30480060960121924) < 0.000000000000001)
1232 : {
1233 1851 : poUnit->GetChild(0)->SetValue("Foot_US");
1234 1851 : poUnit->GetChild(1)->SetValue("0.30480060960121924");
1235 : }
1236 :
1237 : /* -------------------------------------------------------------------- */
1238 : /* Remap parameters used for Albers and Mercator. */
1239 : /* -------------------------------------------------------------------- */
1240 14820 : pszProjection = GetAttrValue("PROJECTION");
1241 14820 : poProjCS = GetAttrNode( "PROJCS" );
1242 :
1243 14820 : if( pszProjection != NULL && EQUAL(pszProjection,"Albers") )
1244 : GetRoot()->applyRemapper(
1245 : "PARAMETER", (char **)apszAlbersMapping + 1,
1246 102 : (char **)apszAlbersMapping + 0, 2 );
1247 :
1248 14820 : if( pszProjection != NULL
1249 : && (EQUAL(pszProjection,SRS_PT_EQUIDISTANT_CONIC) ||
1250 : EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) ||
1251 : EQUAL(pszProjection,SRS_PT_AZIMUTHAL_EQUIDISTANT) ||
1252 : EQUAL(pszProjection,SRS_PT_SINUSOIDAL) ||
1253 : EQUAL(pszProjection,SRS_PT_ROBINSON) ) )
1254 : GetRoot()->applyRemapper(
1255 : "PARAMETER", (char **)apszECMapping + 1,
1256 77 : (char **)apszECMapping + 0, 2 );
1257 :
1258 14820 : if( pszProjection != NULL && EQUAL(pszProjection,"Mercator") )
1259 : GetRoot()->applyRemapper(
1260 : "PARAMETER",
1261 : (char **)apszMercatorMapping + 1,
1262 44 : (char **)apszMercatorMapping + 0, 2 );
1263 :
1264 14820 : if( pszProjection != NULL
1265 : && EQUALN(pszProjection,"Stereographic_",14)
1266 : && EQUALN(pszProjection+strlen(pszProjection)-5,"_Pole",5) )
1267 : GetRoot()->applyRemapper(
1268 : "PARAMETER",
1269 : (char **)apszPolarStereographicMapping + 1,
1270 80 : (char **)apszPolarStereographicMapping + 0, 2 );
1271 :
1272 14820 : if( pszProjection != NULL && EQUAL(pszProjection,"Plate_Carree") )
1273 0 : if(FindProjParm( SRS_PP_STANDARD_PARALLEL_1, poProjCS ) < 0)
1274 : GetRoot()->applyRemapper(
1275 : "PARAMETER",
1276 : (char **)apszPolarStereographicMapping + 1,
1277 0 : (char **)apszPolarStereographicMapping + 0, 2 );
1278 :
1279 : /* -------------------------------------------------------------------- */
1280 : /* ESRI's Equidistant_Cylindrical does not support the */
1281 : /* latitude_of_origin keyword. */
1282 : /* -------------------------------------------------------------------- */
1283 14820 : if( pszProjection != NULL
1284 : && EQUAL(pszProjection,"Equidistant_Cylindrical") )
1285 : {
1286 33 : if( GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0) != 0.0 )
1287 : {
1288 0 : CPLDebug( "OGR_ESRI", "Equirectangular with non-zero latitude of origin - not supported." );
1289 : }
1290 : else
1291 : {
1292 33 : OGR_SRSNode *poPROJCS = GetAttrNode("PROJCS");
1293 33 : if( poPROJCS )
1294 : poPROJCS->DestroyChild(
1295 33 : FindProjParm( SRS_PP_LATITUDE_OF_ORIGIN ) );
1296 : }
1297 : }
1298 :
1299 : /* -------------------------------------------------------------------- */
1300 : /* Convert SPHEROID name to use underscores instead of spaces. */
1301 : /* -------------------------------------------------------------------- */
1302 : OGR_SRSNode *poSpheroid;
1303 14820 : OGR_SRSNode *poSpheroidChild = NULL;
1304 14820 : poSpheroid = GetAttrNode( "SPHEROID" );
1305 14820 : if( poSpheroid != NULL )
1306 14820 : poSpheroidChild = poSpheroid->GetChild(0);
1307 :
1308 14820 : if( poSpheroidChild != NULL )
1309 : {
1310 : // char *pszNewValue = CPLStrdup(RemapSpheroidName(poSpheroidChild->GetValue()));
1311 14820 : char *pszNewValue = CPLStrdup(poSpheroidChild->GetValue());
1312 :
1313 14820 : MorphNameToESRI( &pszNewValue );
1314 :
1315 14820 : poSpheroidChild->SetValue( pszNewValue );
1316 14820 : CPLFree( pszNewValue );
1317 :
1318 : GetRoot()->applyRemapper( "SPHEROID",
1319 : (char **) apszSpheroidMapping+0,
1320 14820 : (char **) apszSpheroidMapping+1, 2 );
1321 : }
1322 :
1323 14820 : if( poSpheroid != NULL )
1324 14820 : poSpheroidChild = poSpheroid->GetChild(2);
1325 :
1326 14820 : if( poSpheroidChild != NULL )
1327 : {
1328 14820 : const char * dfValue = poSpheroidChild->GetValue();
1329 607038 : for( int i = 0; apszInvFlatteningMapping[i] != NULL; i += 2 )
1330 : {
1331 593107 : if( EQUALN(apszInvFlatteningMapping[i], dfValue, strlen(apszInvFlatteningMapping[i]) ))
1332 : {
1333 889 : poSpheroidChild->SetValue( apszInvFlatteningMapping[i+1] );
1334 889 : break;
1335 : }
1336 : }
1337 : }
1338 :
1339 : /* -------------------------------------------------------------------- */
1340 : /* Try to insert a D_ in front of the datum name. */
1341 : /* -------------------------------------------------------------------- */
1342 : OGR_SRSNode *poDatum;
1343 :
1344 14820 : poDatum = GetAttrNode( "DATUM" );
1345 14820 : if( poDatum != NULL )
1346 14820 : poDatum = poDatum->GetChild(0);
1347 :
1348 14820 : if( poDatum != NULL )
1349 : {
1350 14820 : const char* pszDatumName = poDatum->GetValue();
1351 14820 : if( !EQUALN(pszDatumName, "D_",2) )
1352 : {
1353 : char *pszNewValue;
1354 :
1355 3043 : pszNewValue = (char *) CPLMalloc(strlen(poDatum->GetValue())+3);
1356 3043 : strcpy( pszNewValue, "D_" );
1357 3043 : strcat( pszNewValue, poDatum->GetValue() );
1358 3043 : poDatum->SetValue( pszNewValue );
1359 3043 : CPLFree( pszNewValue );
1360 : }
1361 : }
1362 :
1363 : /* -------------------------------------------------------------------- */
1364 : /* final check names */
1365 : /* -------------------------------------------------------------------- */
1366 14820 : if( poProjCSNodeChild )
1367 12134 : pszProjCSName = poProjCSNodeChild->GetValue();
1368 :
1369 14820 : if( pszProjCSName )
1370 : {
1371 12134 : pszGcsName = GetAttrValue( "GEOGCS" );
1372 12134 : if(pszGcsName && !EQUALN( pszGcsName, "GCS_", 4 ) )
1373 : {
1374 5930 : char* newGcsName = (char *) CPLMalloc(strlen(pszGcsName) + 5);
1375 5930 : strcpy( newGcsName, "GCS_" );
1376 5930 : strcat(newGcsName, pszGcsName);
1377 5930 : SetNewName( this, "GEOGCS", newGcsName );
1378 5930 : CPLFree( newGcsName );
1379 5930 : pszGcsName = GetAttrValue("GEOGCS" );
1380 : }
1381 12134 : RemapGeogCSName(this, pszGcsName);
1382 :
1383 : // Specific processing and remapping
1384 12134 : pszProjection = GetAttrValue("PROJECTION");
1385 12134 : if(pszProjection)
1386 : {
1387 12134 : if(EQUAL(pszProjection,"Lambert_Conformal_Conic"))
1388 : {
1389 2723 : if(FindProjParm( SRS_PP_STANDARD_PARALLEL_2, poProjCS ) < 0 )
1390 : {
1391 288 : int iChild = FindProjParm( SRS_PP_LATITUDE_OF_ORIGIN, poProjCS );
1392 288 : int iChild1 = FindProjParm( SRS_PP_STANDARD_PARALLEL_1, poProjCS );
1393 288 : if( iChild >= 0 && iChild1 < 0 )
1394 : {
1395 151 : const OGR_SRSNode *poParameter = poProjCS->GetChild(iChild);
1396 151 : if( poParameter )
1397 : {
1398 151 : OGR_SRSNode *poNewParm = new OGR_SRSNode( "PARAMETER" );
1399 302 : poNewParm->AddChild( new OGR_SRSNode( "standard_parallel_1" ) );
1400 151 : poNewParm->AddChild( new OGR_SRSNode( poParameter->GetChild(1)->GetValue() ) );
1401 151 : poProjCS->AddChild( poNewParm );
1402 : }
1403 : }
1404 : }
1405 : }
1406 :
1407 12134 : if(EQUAL(pszProjection,"Plate_Carree"))
1408 : {
1409 0 : int iChild = FindProjParm( SRS_PP_STANDARD_PARALLEL_1, poProjCS );
1410 0 : if(iChild < 0)
1411 0 : iChild = FindProjParm( SRS_PP_PSEUDO_STD_PARALLEL_1, poProjCS );
1412 :
1413 0 : if(iChild >= 0)
1414 : {
1415 0 : const OGR_SRSNode *poParameter = poProjCS->GetChild(iChild);
1416 0 : if(!EQUAL(poParameter->GetChild(1)->GetValue(), "0.0") && !EQUAL(poParameter->GetChild(1)->GetValue(), "0"))
1417 : {
1418 0 : SetNode( "PROJCS|PROJECTION", "Equidistant_Cylindrical" );
1419 0 : pszProjection = GetAttrValue("PROJECTION");
1420 : }
1421 : }
1422 : }
1423 12134 : DeleteParamBasedOnPrjName( this, pszProjection, (char **)apszDeleteParametersBasedOnProjection);
1424 12134 : AddParamBasedOnPrjName( this, pszProjection, (char **)apszAddParametersBasedOnProjection);
1425 12134 : RemapPValuesBasedOnProjCSAndPName( this, pszProjection, (char **)apszParamValueMapping);
1426 12134 : RemapPNamesBasedOnProjCSAndPName( this, pszProjection, (char **)apszParamNameMapping);
1427 : }
1428 : }
1429 :
1430 14820 : return OGRERR_NONE;
1431 : }
1432 :
1433 : /************************************************************************/
1434 : /* OSRMorphToESRI() */
1435 : /************************************************************************/
1436 :
1437 : /**
1438 : * \brief Convert in place to ESRI WKT format.
1439 : *
1440 : * This function is the same as the C++ method OGRSpatialReference::morphToESRI()
1441 : */
1442 14483 : OGRErr OSRMorphToESRI( OGRSpatialReferenceH hSRS )
1443 :
1444 : {
1445 14483 : VALIDATE_POINTER1( hSRS, "OSRMorphToESRI", CE_Failure );
1446 :
1447 14483 : return ((OGRSpatialReference *) hSRS)->morphToESRI();
1448 : }
1449 :
1450 : /************************************************************************/
1451 : /* morphFromESRI() */
1452 : /* */
1453 : /* modify this definition from the ESRI definition of WKT to */
1454 : /* the "Standard" definition. */
1455 : /************************************************************************/
1456 :
1457 : /**
1458 : * \brief Convert in place from ESRI WKT format.
1459 : *
1460 : * The value notes of this coordinate system are modified in various manners
1461 : * to adhere more closely to the WKT standard. This mostly involves
1462 : * translating a variety of ESRI names for projections, arguments and
1463 : * datums to "standard" names, as defined by Adam Gawne-Cain's reference
1464 : * translation of EPSG to WKT for the CT specification.
1465 : *
1466 : * Starting with GDAL 1.9.0, missing parameters in TOWGS84, DATUM or GEOGCS
1467 : * nodes can be added to the WKT, comparing existing WKT parameters to GDAL's
1468 : * databases. Note that this optional procedure is very conservative and should
1469 : * not introduce false information into the WKT defintion (altough caution
1470 : * should be advised when activating it). Needs the Configuration Option
1471 : * GDAL_FIX_ESRI_WKT be set to one of the following values (TOWGS84 is
1472 : * recommended for proper datum shift calculations):
1473 : *
1474 : * <b>GDAL_FIX_ESRI_WKT values</b>
1475 : * <table border="0">
1476 : * <tr><td> </td><td><b>TOWGS84</b></td><td> </td><td>
1477 : * Adds missing TOWGS84 parameters (necessary for datum transformations),
1478 : * based on named datum and spheroid values.</td></tr>
1479 : * <tr><td> </td><td><b>DATUM</b></td><td> </td><td>
1480 : * Adds EPSG AUTHORITY nodes and sets SPHEROID name to OGR spec.</td></tr>
1481 : * <tr><td> </td><td><b>GEOGCS</b></td><td> </td><td>
1482 : * Adds EPSG AUTHORITY nodes and sets GEOGCS, DATUM and SPHEROID
1483 : * names to OGR spec. Effectively replaces GEOGCS node with the result of
1484 : * importFromEPSG(n), using EPSG code n corresponding to the existing GEOGCS.
1485 : * Does not impact PROJCS values.</td></tr>
1486 : * </table>
1487 : *
1488 : * This does the same as the C function OSRMorphFromESRI().
1489 : *
1490 : * @return OGRERR_NONE unless something goes badly wrong.
1491 : */
1492 :
1493 15101 : OGRErr OGRSpatialReference::morphFromESRI()
1494 :
1495 : {
1496 15101 : OGRErr eErr = OGRERR_NONE;
1497 : OGR_SRSNode *poDatum;
1498 15101 : char *pszDatumOrig = NULL;
1499 :
1500 15101 : if( GetRoot() == NULL )
1501 0 : return OGRERR_NONE;
1502 :
1503 15101 : InitDatumMappingTable();
1504 :
1505 : /* -------------------------------------------------------------------- */
1506 : /* Save original datum name for later */
1507 : /* -------------------------------------------------------------------- */
1508 15101 : poDatum = GetAttrNode( "DATUM" );
1509 15101 : if( poDatum != NULL )
1510 : {
1511 15101 : poDatum = poDatum->GetChild(0);
1512 15101 : pszDatumOrig = CPLStrdup( poDatum->GetValue() );
1513 : }
1514 :
1515 : /* -------------------------------------------------------------------- */
1516 : /* Translate DATUM keywords that are oddly named. */
1517 : /* -------------------------------------------------------------------- */
1518 : GetRoot()->applyRemapper( "DATUM",
1519 : (char **)papszDatumMapping+1,
1520 15101 : (char **)papszDatumMapping+2, 3 );
1521 :
1522 : /* -------------------------------------------------------------------- */
1523 : /* Try to remove any D_ in front of the datum name. */
1524 : /* -------------------------------------------------------------------- */
1525 15101 : poDatum = GetAttrNode( "DATUM" );
1526 15101 : if( poDatum != NULL )
1527 15101 : poDatum = poDatum->GetChild(0);
1528 :
1529 15101 : if( poDatum != NULL )
1530 : {
1531 15101 : if( EQUALN(poDatum->GetValue(),"D_",2) )
1532 : {
1533 3032 : char *pszNewValue = CPLStrdup( poDatum->GetValue() + 2 );
1534 3032 : poDatum->SetValue( pszNewValue );
1535 3032 : CPLFree( pszNewValue );
1536 : }
1537 : }
1538 :
1539 : /* -------------------------------------------------------------------- */
1540 : /* Translate some SPHEROID keywords that are oddly named. */
1541 : /* -------------------------------------------------------------------- */
1542 : GetRoot()->applyRemapper( "SPHEROID",
1543 : (char **)apszSpheroidMapping+1,
1544 15101 : (char **)apszSpheroidMapping+0, 2 );
1545 :
1546 : /* -------------------------------------------------------------------- */
1547 : /* Split Lambert_Conformal_Conic into 1SP or 2SP form. */
1548 : /* */
1549 : /* See bugzilla.remotesensing.org/show_bug.cgi?id=187 */
1550 : /* */
1551 : /* We decide based on whether it has 2SPs. We used to assume */
1552 : /* 1SP if it had a scale factor but that turned out to be a */
1553 : /* poor test. */
1554 : /* -------------------------------------------------------------------- */
1555 15101 : const char *pszProjection = GetAttrValue("PROJECTION");
1556 :
1557 15101 : if( pszProjection != NULL
1558 : && EQUAL(pszProjection,"Lambert_Conformal_Conic") )
1559 : {
1560 2750 : if( GetProjParm( SRS_PP_STANDARD_PARALLEL_1, 1000.0 ) != 1000.0
1561 : && GetProjParm( SRS_PP_STANDARD_PARALLEL_2, 1000.0 ) != 1000.0 )
1562 : SetNode( "PROJCS|PROJECTION",
1563 2462 : SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP );
1564 : else
1565 : SetNode( "PROJCS|PROJECTION",
1566 288 : SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP );
1567 :
1568 2750 : pszProjection = GetAttrValue("PROJECTION");
1569 : }
1570 :
1571 : /* -------------------------------------------------------------------- */
1572 : /* If we are remapping Hotine_Oblique_Mercator_Azimuth_Center */
1573 : /* add a rectified_grid_angle parameter - to match the azimuth */
1574 : /* I guess. */
1575 : /* -------------------------------------------------------------------- */
1576 15101 : if( pszProjection != NULL
1577 : && EQUAL(pszProjection,"Hotine_Oblique_Mercator_Azimuth_Center") )
1578 : {
1579 : SetProjParm( SRS_PP_RECTIFIED_GRID_ANGLE ,
1580 31 : GetProjParm( SRS_PP_AZIMUTH, 0.0 ) );
1581 31 : FixupOrdering();
1582 : }
1583 :
1584 : /* -------------------------------------------------------------------- */
1585 : /* Remap Albers, Mercator and Polar Stereographic parameters. */
1586 : /* -------------------------------------------------------------------- */
1587 15101 : if( pszProjection != NULL && EQUAL(pszProjection,"Albers") )
1588 : GetRoot()->applyRemapper(
1589 : "PARAMETER", (char **)apszAlbersMapping + 0,
1590 92 : (char **)apszAlbersMapping + 1, 2 );
1591 :
1592 15101 : if( pszProjection != NULL
1593 : && (EQUAL(pszProjection,SRS_PT_EQUIDISTANT_CONIC) ||
1594 : EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) ||
1595 : EQUAL(pszProjection,SRS_PT_AZIMUTHAL_EQUIDISTANT) ||
1596 : EQUAL(pszProjection,SRS_PT_SINUSOIDAL) ||
1597 : EQUAL(pszProjection,SRS_PT_ROBINSON) ) )
1598 : GetRoot()->applyRemapper(
1599 : "PARAMETER", (char **)apszECMapping + 0,
1600 76 : (char **)apszECMapping + 1, 2 );
1601 :
1602 15101 : if( pszProjection != NULL && EQUAL(pszProjection,"Mercator") )
1603 : GetRoot()->applyRemapper(
1604 : "PARAMETER",
1605 : (char **)apszMercatorMapping + 0,
1606 44 : (char **)apszMercatorMapping + 1, 2 );
1607 :
1608 15101 : if( pszProjection != NULL && EQUAL(pszProjection,"Orthographic") )
1609 : GetRoot()->applyRemapper(
1610 : "PARAMETER", (char **)apszOrthographicMapping + 0,
1611 5 : (char **)apszOrthographicMapping + 1, 2 );
1612 :
1613 15101 : if( pszProjection != NULL
1614 : && EQUALN(pszProjection,"Stereographic_",14)
1615 : && EQUALN(pszProjection+strlen(pszProjection)-5,"_Pole",5) )
1616 : GetRoot()->applyRemapper(
1617 : "PARAMETER",
1618 : (char **)apszPolarStereographicMapping + 0,
1619 80 : (char **)apszPolarStereographicMapping + 1, 2 );
1620 :
1621 : /* -------------------------------------------------------------------- */
1622 : /* Remap south and north polar stereographic to one value. */
1623 : /* -------------------------------------------------------------------- */
1624 15101 : if( pszProjection != NULL
1625 : && EQUALN(pszProjection,"Stereographic_",14)
1626 : && EQUALN(pszProjection+strlen(pszProjection)-5,"_Pole",5) )
1627 : {
1628 80 : SetNode( "PROJCS|PROJECTION", SRS_PT_POLAR_STEREOGRAPHIC );
1629 80 : pszProjection = GetAttrValue("PROJECTION");
1630 : }
1631 :
1632 : /* -------------------------------------------------------------------- */
1633 : /* Remap Double_Stereographic to Oblique_Stereographic. */
1634 : /* -------------------------------------------------------------------- */
1635 15101 : if( pszProjection != NULL
1636 : && EQUAL(pszProjection,"Double_Stereographic") )
1637 : {
1638 60 : SetNode( "PROJCS|PROJECTION", SRS_PT_OBLIQUE_STEREOGRAPHIC );
1639 60 : pszProjection = GetAttrValue("PROJECTION");
1640 : }
1641 :
1642 : /* -------------------------------------------------------------------- */
1643 : /* Remap Equidistant_Cylindrical parameter. It is same as */
1644 : /* Stereographic */
1645 : /* -------------------------------------------------------------------- */
1646 : #ifdef notdef
1647 : if( pszProjection != NULL && EQUAL(pszProjection,"Equidistant_Cylindrical") )
1648 : GetRoot()->applyRemapper(
1649 : "PARAMETER",
1650 : (char **)apszPolarStereographicMapping + 0,
1651 : (char **)apszPolarStereographicMapping + 1, 2 );
1652 : #endif
1653 :
1654 : /* -------------------------------------------------------------------- */
1655 : /* Translate PROJECTION keywords that are misnamed. */
1656 : /* -------------------------------------------------------------------- */
1657 : GetRoot()->applyRemapper( "PROJECTION",
1658 : (char **)apszProjMapping,
1659 15101 : (char **)apszProjMapping+1, 2 );
1660 :
1661 : /* -------------------------------------------------------------------- */
1662 : /* Translate DATUM keywords that are misnamed. */
1663 : /* -------------------------------------------------------------------- */
1664 15101 : InitDatumMappingTable();
1665 :
1666 : GetRoot()->applyRemapper( "DATUM",
1667 : (char **)papszDatumMapping+1,
1668 15101 : (char **)papszDatumMapping+2, 3 );
1669 :
1670 : /* -------------------------------------------------------------------- */
1671 : /* Fix TOWGS84, DATUM or GEOGCS */
1672 : /* -------------------------------------------------------------------- */
1673 : /* TODO test more ESRI WKT; also add PROJCS */
1674 :
1675 : /* Check GDAL_FIX_ESRI_WKT config option (default=NO); if YES, set to DATUM */
1676 15101 : const char *pszFixWktConfig=CPLGetConfigOption( "GDAL_FIX_ESRI_WKT", "NO" );
1677 15101 : if ( EQUAL(pszFixWktConfig,"YES") )
1678 0 : pszFixWktConfig = "DATUM";
1679 :
1680 15101 : if( !EQUAL(pszFixWktConfig, "NO") && poDatum != NULL )
1681 : {
1682 : CPLDebug( "OGR_ESRI",
1683 : "morphFromESRI() looking for missing TOWGS84, datum=%s, config=%s",
1684 5155 : pszDatumOrig, pszFixWktConfig );
1685 :
1686 : /* Special case for WGS84 and other common GCS? */
1687 :
1688 2208287 : for( int i = 0; DMGetESRIName(i) != NULL; i++ )
1689 : {
1690 : /* we found the ESRI datum name in the map */
1691 2207270 : if( EQUAL(DMGetESRIName(i),pszDatumOrig) )
1692 : {
1693 4265 : const char *pszFilename = NULL;
1694 4265 : char **papszRecord = NULL;
1695 :
1696 : /* look for GEOGCS corresponding to this datum */
1697 4265 : pszFilename = CSVFilename("gcs.csv");
1698 : papszRecord = CSVScanFileByName( pszFilename, "DATUM_CODE",
1699 4265 : DMGetEPSGCode(i), CC_Integer );
1700 4265 : if ( papszRecord != NULL )
1701 : {
1702 : /* make sure we got a valid EPSG code and it is not DEPRECATED */
1703 : int nGeogCS = atoi( CSLGetField( papszRecord,
1704 4265 : CSVGetFileFieldId(pszFilename,"COORD_REF_SYS_CODE")) );
1705 : // int bDeprecated = atoi( CSLGetField( papszRecord,
1706 : // CSVGetFileFieldId(pszFilename,"DEPRECATED")) );
1707 :
1708 4265 : CPLDebug( "OGR_ESRI", "morphFromESRI() got GEOGCS node #%d", nGeogCS );
1709 :
1710 : // if ( nGeogCS >= 1 && bDeprecated == 0 )
1711 4265 : if ( nGeogCS >= 1 )
1712 : {
1713 4265 : OGRSpatialReference oSRSTemp;
1714 4265 : if ( oSRSTemp.importFromEPSG( nGeogCS ) == OGRERR_NONE )
1715 : {
1716 : /* make clone of GEOGCS and strip CT parms for testing */
1717 4265 : OGRSpatialReference *poSRSTemp2 = NULL;
1718 4265 : int bIsSame = FALSE;
1719 4265 : char *pszOtherValue = NULL;
1720 : double dfThisValue, dfOtherValue;
1721 4265 : OGR_SRSNode *poNode = NULL;
1722 :
1723 4265 : poSRSTemp2 = oSRSTemp.CloneGeogCS();
1724 4265 : poSRSTemp2->StripCTParms();
1725 4265 : bIsSame = this->IsSameGeogCS( poSRSTemp2 );
1726 4265 : exportToWkt ( &pszOtherValue );
1727 : CPLDebug( "OGR_ESRI",
1728 : "morphFromESRI() got SRS %s, matching: %d",
1729 4265 : pszOtherValue, bIsSame );
1730 4265 : CPLFree( pszOtherValue );
1731 4265 : delete poSRSTemp2;
1732 :
1733 : /* clone GEOGCS from original if they match and if allowed */
1734 4265 : if ( EQUAL(pszFixWktConfig,"GEOGCS")
1735 : && bIsSame )
1736 : {
1737 772 : this->CopyGeogCSFrom( &oSRSTemp );
1738 : CPLDebug( "OGR_ESRI",
1739 : "morphFromESRI() cloned GEOGCS from EPSG:%d",
1740 772 : nGeogCS );
1741 : /* exit loop */
1742 : break;
1743 : }
1744 : /* else try to copy only DATUM or TOWGS84
1745 : we got here either because of config option or
1746 : GEOGCS are not strictly equal */
1747 3493 : else if ( EQUAL(pszFixWktConfig,"GEOGCS") ||
1748 : EQUAL(pszFixWktConfig,"DATUM") ||
1749 : EQUAL(pszFixWktConfig,"TOWGS84") )
1750 : {
1751 : /* test for matching SPHEROID, because there can be 2 datums with same ESRI name
1752 : but different spheroids (e.g. EPSG:4618 and EPSG:4291) - see bug #4345 */
1753 : /* instead of testing for matching SPHEROID name (which can be error-prone), test
1754 : for matching parameters (semi-major and inverse flattening ) - see bug #4673 */
1755 3493 : bIsSame = TRUE;
1756 3493 : dfThisValue = this->GetSemiMajor();
1757 3493 : dfOtherValue = oSRSTemp.GetSemiMajor();
1758 3493 : if ( ABS( dfThisValue - dfOtherValue ) > 0.01 )
1759 13 : bIsSame = FALSE;
1760 : CPLDebug( "OGR_ESRI",
1761 : "morphFromESRI() SemiMajor: this = %.15g other = %.15g",
1762 3493 : dfThisValue, dfOtherValue );
1763 3493 : dfThisValue = this->GetInvFlattening();
1764 3493 : dfOtherValue = oSRSTemp.GetInvFlattening();
1765 3493 : if ( ABS( dfThisValue - dfOtherValue ) > 0.0001 )
1766 33 : bIsSame = FALSE;
1767 : CPLDebug( "OGR_ESRI",
1768 : "morphFromESRI() InvFlattening: this = %g other = %g",
1769 3493 : dfThisValue, dfOtherValue );
1770 :
1771 3493 : if ( bIsSame )
1772 : {
1773 : /* test for matching PRIMEM, because there can be 2 datums with same ESRI name
1774 : but different prime meridian (e.g. EPSG:4218 and EPSG:4802) - see bug #4378 */
1775 : /* instead of testing for matching PRIMEM name (which can be error-prone), test
1776 : for matching value - see bug #4673 */
1777 3460 : dfThisValue = this->GetPrimeMeridian();
1778 3460 : dfOtherValue = oSRSTemp.GetPrimeMeridian();
1779 : CPLDebug( "OGR_ESRI",
1780 : "morphFromESRI() PRIMEM: this = %.15g other = %.15g",
1781 3460 : dfThisValue, dfOtherValue );
1782 3460 : if ( ABS( dfThisValue - dfOtherValue ) > 0.0001 )
1783 94 : bIsSame = FALSE;
1784 : }
1785 :
1786 : /* found a matching spheroid */
1787 3493 : if ( bIsSame )
1788 : {
1789 : /* clone DATUM */
1790 6732 : if ( EQUAL(pszFixWktConfig,"GEOGCS") ||
1791 : EQUAL(pszFixWktConfig,"DATUM") )
1792 : {
1793 3366 : OGR_SRSNode *poGeogCS = this->GetAttrNode( "GEOGCS" );
1794 3366 : const OGR_SRSNode *poDatumOther = oSRSTemp.GetAttrNode( "DATUM" );
1795 3366 : if ( poGeogCS && poDatumOther )
1796 : {
1797 : /* make sure we preserve the position of the DATUM node */
1798 3366 : int nPos = poGeogCS->FindChild( "DATUM" );
1799 3366 : if ( nPos >= 0 )
1800 : {
1801 3366 : poGeogCS->DestroyChild( nPos );
1802 3366 : poGeogCS->InsertChild( poDatumOther->Clone(), nPos );
1803 : CPLDebug( "OGR_ESRI",
1804 : "morphFromESRI() cloned DATUM from EPSG:%d",
1805 3366 : nGeogCS );
1806 : }
1807 : }
1808 : }
1809 : /* just copy TOWGS84 */
1810 0 : else if ( EQUAL(pszFixWktConfig,"TOWGS84") )
1811 : {
1812 0 : poNode=oSRSTemp.GetAttrNode( "DATUM|TOWGS84" );
1813 0 : if ( poNode )
1814 : {
1815 0 : poNode=poNode->Clone();
1816 0 : GetAttrNode( "DATUM" )->AddChild( poNode );
1817 : CPLDebug( "OGR_ESRI",
1818 : "morphFromESRI() found missing TOWGS84 from EPSG:%d",
1819 0 : nGeogCS );
1820 : }
1821 : }
1822 : /* exit loop */
1823 : break;
1824 : }
1825 : }
1826 0 : }
1827 : }
1828 : }
1829 : }
1830 : }
1831 : }
1832 :
1833 15101 : CPLFree( pszDatumOrig );
1834 :
1835 15101 : return eErr;
1836 : }
1837 :
1838 : /************************************************************************/
1839 : /* OSRMorphFromESRI() */
1840 : /************************************************************************/
1841 :
1842 : /**
1843 : * \brief Convert in place from ESRI WKT format.
1844 : *
1845 : * This function is the same as the C++ method OGRSpatialReference::morphFromESRI()
1846 : */
1847 14440 : OGRErr OSRMorphFromESRI( OGRSpatialReferenceH hSRS )
1848 :
1849 : {
1850 14440 : VALIDATE_POINTER1( hSRS, "OSRMorphFromESRI", CE_Failure );
1851 :
1852 14440 : return ((OGRSpatialReference *) hSRS)->morphFromESRI();
1853 : }
1854 :
1855 : /************************************************************************/
1856 : /* SetNewName() */
1857 : /* */
1858 : /* Set an esri name */
1859 : /************************************************************************/
1860 5930 : void SetNewName( OGRSpatialReference* pOgr, const char* keyName, const char* newName )
1861 : {
1862 5930 : OGR_SRSNode *poNode = pOgr->GetAttrNode( keyName );
1863 5930 : OGR_SRSNode *poNodeChild = NULL;
1864 5930 : if(poNode)
1865 5930 : poNodeChild = poNode->GetChild(0);
1866 5930 : if( poNodeChild)
1867 5930 : poNodeChild->SetValue( newName);
1868 5930 : }
1869 :
1870 : /************************************************************************/
1871 : /* RemapImgWGSProjcsName() */
1872 : /* */
1873 : /* Convert Img projcs names to ESRI style */
1874 : /************************************************************************/
1875 0 : int RemapImgWGSProjcsName( OGRSpatialReference* pOgr, const char* pszProjCSName, const char* pszProgCSName )
1876 : {
1877 0 : if(EQUAL(pszProgCSName, "WGS_1972") || EQUAL(pszProgCSName, "WGS_1984") )
1878 : {
1879 0 : char* newName = (char *) CPLMalloc(strlen(pszProjCSName) + 10);
1880 0 : sprintf( newName, "%s_", pszProgCSName );
1881 0 : strcat(newName, pszProjCSName);
1882 0 : SetNewName( pOgr, "PROJCS", newName );
1883 0 : CPLFree( newName );
1884 0 : return 1;
1885 : }
1886 0 : return -1;
1887 : }
1888 :
1889 : /************************************************************************/
1890 : /* RemapImgUTMNames() */
1891 : /* */
1892 : /* Convert Img UTM names to ESRI style */
1893 : /************************************************************************/
1894 :
1895 0 : int RemapImgUTMNames( OGRSpatialReference* pOgr, const char* pszProjCSName, const char* pszProgCSName,
1896 : char **mappingTable )
1897 : {
1898 : long i;
1899 0 : long iIndex = -1;
1900 0 : for( i = 0; mappingTable[i] != NULL; i += 5 )
1901 : {
1902 0 : if( EQUAL(pszProjCSName, mappingTable[i]) )
1903 : {
1904 0 : long j = i;
1905 0 : while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
1906 : {
1907 0 : if( EQUAL(pszProgCSName, mappingTable[j+1]) )
1908 : {
1909 0 : iIndex = j;
1910 0 : break;
1911 : }
1912 0 : j += 5;
1913 : }
1914 0 : if (iIndex >= 0)
1915 0 : break;
1916 : }
1917 : }
1918 0 : if(iIndex >= 0)
1919 : {
1920 0 : OGR_SRSNode *poNode = pOgr->GetAttrNode( "PROJCS" );
1921 0 : OGR_SRSNode *poNodeChild = NULL;
1922 0 : if(poNode)
1923 0 : poNodeChild = poNode->GetChild(0);
1924 0 : if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
1925 0 : poNodeChild->SetValue( mappingTable[iIndex+2]);
1926 :
1927 0 : poNode = pOgr->GetAttrNode( "GEOGCS" );
1928 0 : poNodeChild = NULL;
1929 0 : if(poNode)
1930 0 : poNodeChild = poNode->GetChild(0);
1931 0 : if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
1932 0 : poNodeChild->SetValue( mappingTable[iIndex+3]);
1933 :
1934 0 : poNode = pOgr->GetAttrNode( "DATUM" );
1935 0 : poNodeChild = NULL;
1936 0 : if(poNode)
1937 0 : poNodeChild = poNode->GetChild(0);
1938 0 : if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
1939 0 : poNodeChild->SetValue( mappingTable[iIndex+4]);
1940 : }
1941 0 : return iIndex;
1942 : }
1943 :
1944 : /************************************************************************/
1945 : /* RemapNameBasedOnKeyName() */
1946 : /* */
1947 : /* Convert a name to ESRI style name */
1948 : /************************************************************************/
1949 :
1950 12022 : int RemapNameBasedOnKeyName( OGRSpatialReference* pOgr, const char* pszName, const char* pszkeyName,
1951 : char **mappingTable )
1952 : {
1953 : long i;
1954 12022 : long iIndex = -1;
1955 1218355 : for( i = 0; mappingTable[i] != NULL; i += 2 )
1956 : {
1957 1206840 : if( EQUAL(pszName, mappingTable[i]) )
1958 : {
1959 507 : iIndex = i;
1960 507 : break;
1961 : }
1962 : }
1963 12022 : if(iIndex >= 0)
1964 : {
1965 507 : OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyName );
1966 507 : OGR_SRSNode *poNodeChild = NULL;
1967 507 : if(poNode)
1968 507 : poNodeChild = poNode->GetChild(0);
1969 507 : if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
1970 507 : poNodeChild->SetValue( mappingTable[iIndex+1]);
1971 : }
1972 12022 : return iIndex;
1973 : }
1974 :
1975 : /************************************************************************/
1976 : /* RemapNamesBasedOnTwo() */
1977 : /* */
1978 : /* Convert a name to ESRI style name */
1979 : /************************************************************************/
1980 :
1981 35725 : int RemapNamesBasedOnTwo( OGRSpatialReference* pOgr, const char* name1, const char* name2,
1982 : char **mappingTable, long nTableStepSize,
1983 : char** pszkeyNames, long nKeys )
1984 : {
1985 : long i, n, n1;
1986 35725 : long iIndex = -1;
1987 342878 : for( i = 0; mappingTable[i] != NULL; i += nTableStepSize )
1988 : {
1989 307274 : n = strlen(name1);
1990 307274 : n1 = strlen(mappingTable[i]);
1991 307274 : if( EQUALN(name1, mappingTable[i], n1<=n? n1 : n) )
1992 : {
1993 333 : long j = i;
1994 965 : while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
1995 : {
1996 420 : if( EQUALN(name2, mappingTable[j+1], strlen(mappingTable[j+1])) )
1997 : {
1998 121 : iIndex = j;
1999 121 : break;
2000 : }
2001 299 : j += 3;
2002 : }
2003 333 : if (iIndex >= 0)
2004 121 : break;
2005 : }
2006 : }
2007 35725 : if(iIndex >= 0)
2008 : {
2009 242 : for( i = 0; i < nKeys; i ++ )
2010 : {
2011 121 : OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyNames[i] );
2012 121 : OGR_SRSNode *poNodeChild = NULL;
2013 121 : if(poNode)
2014 121 : poNodeChild = poNode->GetChild(0);
2015 121 : if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
2016 121 : poNodeChild->SetValue( mappingTable[iIndex+i+2]);
2017 : }
2018 :
2019 : }
2020 35725 : return iIndex;
2021 : }
2022 :
2023 : /************************************************************************/
2024 : /* RemapPValuesBasedOnProjCSAndPName() */
2025 : /* */
2026 : /* Convert a parameters to ESRI style name */
2027 : /************************************************************************/
2028 :
2029 12134 : int RemapPValuesBasedOnProjCSAndPName( OGRSpatialReference* pOgr, const char* pszProgCSName,
2030 : char **mappingTable )
2031 : {
2032 12134 : long ret = 0;
2033 12134 : OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
2034 83312 : for( int i = 0; mappingTable[i] != NULL; i += 4 )
2035 : {
2036 223738 : while( mappingTable[i] != NULL && EQUALN(pszProgCSName, mappingTable[i], strlen(mappingTable[i])) )
2037 : {
2038 : OGR_SRSNode *poParm;
2039 58232 : const char* pszParamName = mappingTable[i+1];
2040 58232 : const char* pszParamValue = mappingTable[i+2];
2041 587874 : for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
2042 : {
2043 529642 : poParm = poPROJCS->GetChild( iChild );
2044 :
2045 529642 : if( EQUAL(poParm->GetValue(),"PARAMETER")
2046 : && poParm->GetChildCount() == 2
2047 : && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName)
2048 : && EQUALN(poParm->GetChild(1)->GetValue(),pszParamValue, strlen(pszParamValue) ) )
2049 : {
2050 0 : poParm->GetChild(1)->SetValue( mappingTable[i+3] );
2051 0 : break;
2052 : }
2053 : }
2054 58232 : ret ++;
2055 58232 : i += 4;
2056 : }
2057 82753 : if (ret > 0)
2058 11575 : break;
2059 : }
2060 12134 : return ret;
2061 : }
2062 :
2063 : /************************************************************************/
2064 : /* RemapPNamesBasedOnProjCSAndPName() */
2065 : /* */
2066 : /* Convert a parameters to ESRI style name */
2067 : /************************************************************************/
2068 :
2069 12134 : int RemapPNamesBasedOnProjCSAndPName( OGRSpatialReference* pOgr, const char* pszProgCSName,
2070 : char **mappingTable )
2071 : {
2072 12134 : long ret = 0;
2073 12134 : OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
2074 108754 : for( int i = 0; mappingTable[i] != NULL; i += 3 )
2075 : {
2076 193489 : while( mappingTable[i] != NULL && EQUALN(pszProgCSName, mappingTable[i], strlen(mappingTable[i])) )
2077 : {
2078 : OGR_SRSNode *poParm;
2079 121 : const char* pszParamName = mappingTable[i+1];
2080 1046 : for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
2081 : {
2082 937 : poParm = poPROJCS->GetChild( iChild );
2083 :
2084 937 : if( EQUAL(poParm->GetValue(),"PARAMETER")
2085 : && poParm->GetChildCount() == 2
2086 : && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) )
2087 : {
2088 12 : poParm->GetChild(0)->SetValue( mappingTable[i+2] );
2089 12 : break;
2090 : }
2091 : }
2092 121 : ret ++;
2093 121 : i += 3;
2094 : }
2095 96684 : if (ret > 0)
2096 64 : break;
2097 : }
2098 12134 : return ret;
2099 : }
2100 :
2101 : /************************************************************************/
2102 : /* DeleteParamBasedOnPrjName */
2103 : /* */
2104 : /* Delete non-ESRI parameters */
2105 : /************************************************************************/
2106 12134 : int DeleteParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProjectionName,
2107 : char **mappingTable )
2108 : {
2109 12134 : long iIndex = -1, ret = -1;
2110 145608 : for( int i = 0; mappingTable[i] != NULL; i += 2 )
2111 : {
2112 133474 : if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
2113 : {
2114 269 : OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
2115 : OGR_SRSNode *poParm;
2116 269 : const char* pszParamName = mappingTable[i+1];
2117 269 : iIndex = -1;
2118 2002 : for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
2119 : {
2120 1887 : poParm = poPROJCS->GetChild( iChild );
2121 :
2122 1887 : if( EQUAL(poParm->GetValue(),"PARAMETER")
2123 : && poParm->GetChildCount() == 2
2124 : && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) )
2125 : {
2126 154 : iIndex = iChild;
2127 154 : break;
2128 : }
2129 : }
2130 269 : if(iIndex >= 0)
2131 : {
2132 154 : poPROJCS->DestroyChild( iIndex );
2133 154 : ret ++;
2134 : }
2135 : }
2136 : }
2137 12134 : return ret;
2138 : }
2139 : /************************************************************************/
2140 : /* AddParamBasedOnPrjName() */
2141 : /* */
2142 : /* Add ESRI style parameters */
2143 : /************************************************************************/
2144 12134 : int AddParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProjectionName,
2145 : char **mappingTable )
2146 : {
2147 12134 : long ret = -1;
2148 12134 : OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
2149 36402 : for( int i = 0; mappingTable[i] != NULL; i += 3 )
2150 : {
2151 24268 : if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
2152 : {
2153 : OGR_SRSNode *poParm;
2154 115 : int exist = 0;
2155 1029 : for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
2156 : {
2157 914 : poParm = poPROJCS->GetChild( iChild );
2158 :
2159 1368 : if( EQUAL(poParm->GetValue(),"PARAMETER")
2160 : && poParm->GetChildCount() == 2
2161 454 : && EQUAL(poParm->GetChild(0)->GetValue(),mappingTable[i+1]) )
2162 45 : exist = 1;
2163 : }
2164 115 : if(!exist)
2165 : {
2166 70 : poParm = new OGR_SRSNode( "PARAMETER" );
2167 140 : poParm->AddChild( new OGR_SRSNode( mappingTable[i+1] ) );
2168 140 : poParm->AddChild( new OGR_SRSNode( mappingTable[i+2] ) );
2169 70 : poPROJCS->AddChild( poParm );
2170 70 : ret ++;
2171 : }
2172 : }
2173 : }
2174 12134 : return ret;
2175 : }
2176 :
2177 : /************************************************************************/
2178 : /* RemapGeogCSName() */
2179 : /* */
2180 : /* Convert names to ESRI style */
2181 : /************************************************************************/
2182 12134 : int RemapGeogCSName( OGRSpatialReference* pOgr, const char *pszGeogCSName )
2183 : {
2184 : static const char *keyNamesG[] = {
2185 : "GEOGCS"};
2186 12134 : int ret = -1;
2187 :
2188 12134 : const char* pszUnitName = pOgr->GetAttrValue( "GEOGCS|UNIT");
2189 12134 : if(pszUnitName)
2190 12134 : ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszUnitName, (char**)apszGcsNameMappingBasedOnUnit, 3, (char**)keyNamesG, 1);
2191 12134 : if(ret < 0)
2192 : {
2193 12076 : const char* pszPrimeName = pOgr->GetAttrValue("PRIMEM");
2194 12076 : if(pszPrimeName)
2195 12076 : ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszPrimeName, (char**)apszGcsNameMappingBasedPrime, 3, (char**)keyNamesG, 1);
2196 12076 : if(ret < 0)
2197 12022 : ret = RemapNameBasedOnKeyName( pOgr, pszGeogCSName+4, "GEOGCS", (char**)apszGcsNameMapping);
2198 : }
2199 12134 : if(ret < 0)
2200 : {
2201 11515 : const char* pszProjCS = pOgr->GetAttrValue( "PROJCS" );
2202 11515 : ret = RemapNamesBasedOnTwo( pOgr, pszProjCS, pszGeogCSName, (char**)apszGcsNameMappingBasedOnProjCS, 3, (char**)keyNamesG, 1);
2203 : }
2204 12134 : return ret;
2205 : }
2206 :
2207 : /************************************************************************/
2208 : /* ImportFromESRIStatePlaneWKT() */
2209 : /* */
2210 : /* Search a ESRI State Plane WKT and import it. */
2211 : /************************************************************************/
2212 :
2213 3 : OGRErr OGRSpatialReference::ImportFromESRIStatePlaneWKT( int code, const char* datumName, const char* unitsName, int pcsCode, const char* csName )
2214 : {
2215 : int i;
2216 3 : long searchCode = -1;
2217 :
2218 : /* if the CS name is known */
2219 3 : if (code == 0 && !datumName && !unitsName && pcsCode == 32767 && csName)
2220 : {
2221 : char codeS[10];
2222 0 : if (FindCodeFromDict( "esri_StatePlane_extra.wkt", csName, codeS ) != OGRERR_NONE)
2223 0 : return OGRERR_FAILURE;
2224 0 : return importFromDict( "esri_StatePlane_extra.wkt", codeS);
2225 : }
2226 :
2227 : /* Find state plane prj str by pcs code only */
2228 3 : if( code == 0 && !datumName && pcsCode != 32767 )
2229 : {
2230 :
2231 0 : int unitCode = 1;
2232 0 : if( EQUAL(unitsName, "international_feet") )
2233 0 : unitCode = 3;
2234 0 : else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
2235 0 : unitCode = 2;
2236 0 : for(i=0; statePlanePcsCodeToZoneCode[i] != 0; i+=2)
2237 : {
2238 0 : if( pcsCode == statePlanePcsCodeToZoneCode[i] )
2239 : {
2240 0 : searchCode = statePlanePcsCodeToZoneCode[i+1];
2241 0 : int unitIndex = searchCode % 10;
2242 0 : if( (unitCode == 1 && !(unitIndex == 0 || unitIndex == 1))
2243 : || (unitCode == 2 && !(unitIndex == 2 || unitIndex == 3 || unitIndex == 4 ))
2244 : || (unitCode == 3 && !(unitIndex == 5 || unitIndex == 6 )) )
2245 : {
2246 0 : searchCode -= unitIndex;
2247 0 : switch (unitIndex)
2248 : {
2249 : case 0:
2250 : case 3:
2251 : case 5:
2252 0 : if(unitCode == 2)
2253 0 : searchCode += 3;
2254 0 : else if(unitCode == 3)
2255 0 : searchCode += 5;
2256 0 : break;
2257 : case 1:
2258 : case 2:
2259 : case 6:
2260 0 : if(unitCode == 1)
2261 0 : searchCode += 1;
2262 0 : if(unitCode == 2)
2263 0 : searchCode += 2;
2264 0 : else if(unitCode == 3)
2265 0 : searchCode += 6;
2266 0 : break;
2267 : case 4:
2268 0 : if(unitCode == 2)
2269 0 : searchCode += 4;
2270 : break;
2271 : }
2272 : }
2273 0 : break;
2274 : }
2275 : }
2276 : }
2277 : else /* Find state plane prj str by all inputs. */
2278 : {
2279 : /* Need to have a specail EPSG-ESRI zone code mapping first. */
2280 360 : for(i=0; statePlaneZoneMapping[i] != 0; i+=3)
2281 : {
2282 357 : if( code == statePlaneZoneMapping[i]
2283 0 : && (statePlaneZoneMapping[i+1] == -1 || pcsCode == statePlaneZoneMapping[i+1]))
2284 : {
2285 0 : code = statePlaneZoneMapping[i+2];
2286 0 : break;
2287 : }
2288 : }
2289 3 : searchCode = (long)code * 10;
2290 3 : if(EQUAL(datumName, "HARN"))
2291 : {
2292 0 : if( EQUAL(unitsName, "international_feet") )
2293 0 : searchCode += 5;
2294 0 : else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
2295 0 : searchCode += 3;
2296 : }
2297 6 : else if(strstr(datumName, "NAD") && strstr(datumName, "83"))
2298 : {
2299 3 : if( EQUAL(unitsName, "meters") )
2300 0 : searchCode += 1;
2301 3 : else if( EQUAL(unitsName, "international_feet") )
2302 0 : searchCode += 6;
2303 3 : else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
2304 3 : searchCode += 2;
2305 : }
2306 0 : else if(strstr(datumName, "NAD") && strstr(datumName, "27") && !EQUAL(unitsName, "meters"))
2307 : {
2308 0 : searchCode += 4;
2309 : }
2310 : else
2311 0 : searchCode = -1;
2312 : }
2313 3 : if(searchCode > 0)
2314 : {
2315 : char codeS[10];
2316 3 : sprintf(codeS, "%d", (int)searchCode);
2317 3 : return importFromDict( "esri_StatePlane_extra.wkt", codeS);
2318 : }
2319 0 : return OGRERR_FAILURE;
2320 : }
2321 :
2322 : /************************************************************************/
2323 : /* ImportFromESRIWisconsinWKT() */
2324 : /* */
2325 : /* Search a ESRI State Plane WKT and import it. */
2326 : /************************************************************************/
2327 :
2328 0 : OGRErr OGRSpatialReference::ImportFromESRIWisconsinWKT( const char* prjName, double centralMeridian, double latOfOrigin, const char* unitsName, const char* csName )
2329 : {
2330 : /* if the CS name is known */
2331 0 : if (!prjName && !unitsName && csName)
2332 : {
2333 : char codeS[10];
2334 0 : if (FindCodeFromDict( "esri_Wisconsin_extra.wkt", csName, codeS ) != OGRERR_NONE)
2335 0 : return OGRERR_FAILURE;
2336 0 : return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
2337 : }
2338 : double* tableWISCRS;
2339 0 : if(EQUALN(prjName, "Lambert_Conformal_Conic", 22))
2340 0 : tableWISCRS = apszWISCRS_LCC_meter;
2341 0 : else if(EQUAL(prjName, SRS_PT_TRANSVERSE_MERCATOR))
2342 0 : tableWISCRS = apszWISCRS_TM_meter;
2343 : else
2344 0 : return OGRERR_FAILURE;
2345 0 : int k = -1;
2346 0 : for(int i=0; tableWISCRS[i] != 0; i+=3)
2347 : {
2348 0 : if( fabs(centralMeridian - tableWISCRS[i]) <= 0.0000000001 && fabs(latOfOrigin - tableWISCRS[i+1]) <= 0.0000000001)
2349 : {
2350 0 : k = (long)tableWISCRS[i+2];
2351 0 : break;
2352 : }
2353 : }
2354 0 : if(k > 0)
2355 : {
2356 0 : if(!EQUAL(unitsName, "meters"))
2357 0 : k += 100;
2358 : char codeS[10];
2359 0 : sprintf(codeS, "%d", k);
2360 0 : return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
2361 : }
2362 0 : return OGRERR_FAILURE;
2363 : }
2364 :
2365 : /************************************************************************/
2366 : /* FindCodeFromDict() */
2367 : /* */
2368 : /* Find the code from a dict file. */
2369 : /************************************************************************/
2370 0 : static int FindCodeFromDict( const char* pszDictFile, const char* CSName, char* code )
2371 : {
2372 : const char *pszFilename;
2373 : FILE *fp;
2374 0 : OGRErr eErr = OGRERR_UNSUPPORTED_SRS;
2375 :
2376 : /* -------------------------------------------------------------------- */
2377 : /* Find and open file. */
2378 : /* -------------------------------------------------------------------- */
2379 0 : pszFilename = CPLFindFile( "gdal", pszDictFile );
2380 0 : if( pszFilename == NULL )
2381 0 : return OGRERR_UNSUPPORTED_SRS;
2382 :
2383 0 : fp = VSIFOpen( pszFilename, "rb" );
2384 0 : if( fp == NULL )
2385 0 : return OGRERR_UNSUPPORTED_SRS;
2386 :
2387 : /* -------------------------------------------------------------------- */
2388 : /* Process lines. */
2389 : /* -------------------------------------------------------------------- */
2390 : const char *pszLine;
2391 :
2392 0 : while( (pszLine = CPLReadLine(fp)) != NULL )
2393 :
2394 : {
2395 0 : if( pszLine[0] == '#' )
2396 : /* do nothing */;
2397 :
2398 0 : else if( strstr(pszLine,CSName) )
2399 : {
2400 0 : const char* pComma = strchr(pszLine, ',');
2401 0 : if( pComma )
2402 : {
2403 0 : strncpy( code, pszLine, pComma - pszLine);
2404 0 : code[pComma - pszLine] = '\0';
2405 0 : eErr = OGRERR_NONE;
2406 : }
2407 0 : break;
2408 : }
2409 : }
2410 :
2411 : /* -------------------------------------------------------------------- */
2412 : /* Cleanup */
2413 : /* -------------------------------------------------------------------- */
2414 0 : VSIFClose( fp );
2415 :
2416 0 : return eErr;
2417 : }
|