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