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