1 /******************************************************************************
2 * $Id: ogr_srs_pci.cpp 15826 2008-11-27 22:28:25Z warmerdam $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: OGRSpatialReference translation to/from PCI georeferencing
6 * information.
7 * Author: Andrey Kiselev, dron@remotesensing.org
8 *
9 ******************************************************************************
10 * Copyright (c) 2003, Andrey Kiselev <dron@remotesensing.org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_spatialref.h"
32 #include "../port/cpl_conv.h"
33 #include "../port/cpl_csv.h"
34
35 CPL_CVSID("$Id: ogr_srs_pci.cpp 15826 2008-11-27 22:28:25Z warmerdam $");
36
37 typedef struct
38 {
39 const char *pszPCIDatum;
40 int nEPSGCode;
41 double dfSemiMajor;
42 double dfSemiMinor;
43 } PCIDatums;
44
45 static const PCIDatums aoDatums[] =
46 {
47 { "D-01", 4267, 0, 0 }, // NAD27 (USA, NADCON)
48 { "D-03", 4267, 0, 0 }, // NAD27 (Canada, NTv1)
49 { "D-02", 4269, 0, 0 }, // NAD83 (USA, NADCON)
50 { "D-04", 4269, 0, 0 }, // NAD83 (Canada, NTv1)
51 { "D000", 4326, 0, 0 }, // WGS 1984
52 { "D001", 4322, 0, 0 }, // WGS 1972
53 { "D008", 4296, 0, 0 }, // Sudan
54 { "D013", 4601, 0, 0 }, // Antigua Island Astro 1943
55 { "D029", 4202, 0, 0 }, // Australian Geodetic 1966
56 { "D030", 4203, 0, 0 }, // Australian Geodetic 1984
57 { "D033", 4216, 0, 0 }, // Bermuda 1957
58 { "D034", 4165, 0, 0 }, // Bissau
59 { "D036", 4219, 0, 0 }, // Bukit Rimpah
60 { "D038", 4221, 0, 0 }, // Campo Inchauspe
61 { "D040", 4222, 0, 0 }, // Cape
62 { "D042", 4223, 0, 0 }, // Carthage
63 { "D044", 4224, 0, 0 }, // Chua Astro
64 { "D045", 4225, 0, 0 }, // Corrego Alegre
65 { "D046", 4155, 0, 0 }, // Dabola (Guinea)
66 { "D066", 4272, 0, 0 }, // Geodetic Datum 1949 (New Zealand)
67 { "D071", 4255, 0, 0 }, // Herat North (Afghanistan)
68 { "D077", 4239, 0, 0 }, // Indian 1954 (Thailand, Vietnam)
69 { "D078", 4240, 0, 0 }, // Indian 1975 (Thailand)
70 { "D083", 4244, 0, 0 }, // Kandawala (Sri Lanka)
71 { "D085", 4245, 0, 0 }, // Kertau 1948 (West Malaysia & Singapore)
72 { "D088", 4250, 0, 0 }, // Leigon (Ghana)
73 { "D089", 4251, 0, 0 }, // Liberia 1964 (Liberia)
74 { "D092", 4256, 0, 0 }, // Mahe 1971 (Mahe Island)
75 { "D093", 4262, 0, 0 }, // Massawa (Ethiopia (Eritrea))
76 { "D094", 4261, 0, 0 }, // Merchich (Morocco)
77 { "D098", 4604, 0, 0 }, // Montserrat Island Astro 1958 (Montserrat (Leeward Islands))
78 { "D139", 4282, 0, 0 }, // Pointe Noire 1948 (Congo)
79 { "D140", 4615, 0, 0 }, // Porto Santo 1936 (Porto Santo, Madeira Islands)
80 { "D151", 4139, 0, 0 }, // Puerto Rico (Puerto Rico, Virgin Islands)
81 { "D153", 4287, 0, 0 }, // Qornoq (Greenland (South))
82 { "D158", 4292, 0, 0 }, // Sapper Hill 1943 (East Falkland Island)
83 { "D159", 4293, 0, 0 }, // Schwarzeck (Namibia)
84 { "D160", 4616, 0, 0 }, // Selvagem Grande 1938 (Salvage Islands)
85 { "D176", 4297, 0, 0 }, // Tananarive Observatory 1925 (Madagascar)
86 { "D177", 4298, 0, 0 }, // Timbalai 1948 (Brunei, East Malaysia (Sabah, Sarawak))
87 { "D187", 4309, 0, 0 }, // Yacare (Uruguay)
88 { "D188", 4311, 0, 0 }, // Zanderij (Suriname)
89 { "D401", 4124, 0, 0 }, // RT90 (Sweden)
90 { "D501", 4312, 0, 0 }, // MGI (Hermannskogel, Austria)
91 { NULL, 0 }
92 };
93
94 static const PCIDatums aoEllips[] =
95 {
96 { "E000", 7008, 0, 0 }, // Clarke, 1866 (NAD1927)
97 { "E001", 7034, 0, 0 }, // Clarke, 1880
98 { "E002", 7004, 0, 0 }, // Bessel, 1841
99 { "E003", 0, 6378157.5,6356772.2 }, // New International, 1967
100 { "E004", 7022, 0, 0 }, // International, 1924 (Hayford, 1909)
101 { "E005", 7043, 0, 0 }, // WGS, 1972
102 { "E006", 7042, 0, 0 }, // Everest, 1830
103 { "E007", 0, 6378145.,6356759.769356 }, // WGS, 1966
104 { "E008", 7019, 0, 0 }, // GRS, 1980 (NAD1983)
105 { "E009", 7001, 0, 0 }, // Airy, 1830
106 { "E010", 7018, 0, 0 }, // Modified Everest
107 { "E011", 7002, 0, 0 }, // Modified Airy
108 { "E012", 7030, 0, 0 }, // WGS, 1984 (GPS)
109 { "E013", 0, 6378155.,6356773.3205 }, // Southeast Asia
110 { "E014", 7003, 0, 0 }, // Australian National, 1965
111 { "E015", 7024, 0, 0 }, // Krassovsky, 1940
112 { "E016", 7053, 0, 0 }, // Hough
113 { "E017", 0, 6378166.,6356784.283666 }, // Mercury, 1960
114 { "E018", 0, 6378150.,6356768.337303 }, // Modified Mercury, 1968
115 { "E019", 7052, 0, 0}, // normal sphere
116 { "E333", 7046, 0, 0 }, // Bessel 1841 (Japan By Law)
117 { "E600", 0, 6378144.0,6356759.0 }, // D-PAF (Orbits)
118 { "E900", 7006, 0, 0 }, // Bessel, 1841 (Namibia)
119 { "E901", 7044, 0, 0 }, // Everest, 1956
120 { "E902", 7056, 0, 0 }, // Everest, 1969
121 { "E903", 7016, 0, 0 }, // Everest (Sabah & Sarawak)
122 { "E904", 7020, 0, 0 }, // Helmert, 1906
123 { "E905", 0, 6378136.,6356751.301569 }, // SGS 85
124 { "E906", 0, 6378165.,6356783.286959 }, // WGS 60
125 { "E907", 7036, 0, 0 }, // South American, 1969
126 { "E910", 7041, 0, 0 }, // ATS77
127 { NULL, 0 }
128 };
129
130 /************************************************************************/
131 /* PCIGetUOMLengthInfo() */
132 /* */
133 /* Note: This function should eventually also know how to */
134 /* lookup length aliases in the UOM_LE_ALIAS table. */
135 /************************************************************************/
136
137 static int
PCIGetUOMLengthInfo(int nUOMLengthCode,char ** ppszUOMName,double * pdfInMeters)138 PCIGetUOMLengthInfo( int nUOMLengthCode, char **ppszUOMName,
139 double * pdfInMeters )
140
141 {
142 char **papszUnitsRecord;
143 char szSearchKey[24];
144 int iNameField;
145
146 #define UOM_FILENAME CSVFilename( "unit_of_measure.csv" )
147
148 /* -------------------------------------------------------------------- */
149 /* We short cut meter to save work in the most common case. */
150 /* -------------------------------------------------------------------- */
151 if( nUOMLengthCode == 9001 )
152 {
153 if( ppszUOMName != NULL )
154 *ppszUOMName = CPLStrdup( "metre" );
155 if( pdfInMeters != NULL )
156 *pdfInMeters = 1.0;
157
158 return TRUE;
159 }
160
161 /* -------------------------------------------------------------------- */
162 /* Search the units database for this unit. If we don't find */
163 /* it return failure. */
164 /* -------------------------------------------------------------------- */
165 sprintf( szSearchKey, "%d", nUOMLengthCode );
166 papszUnitsRecord =
167 CSVScanFileByName( UOM_FILENAME, "UOM_CODE", szSearchKey, CC_Integer );
168
169 if( papszUnitsRecord == NULL )
170 return FALSE;
171
172 /* -------------------------------------------------------------------- */
173 /* Get the name, if requested. */
174 /* -------------------------------------------------------------------- */
175 if( ppszUOMName != NULL )
176 {
177 iNameField = CSVGetFileFieldId( UOM_FILENAME, "UNIT_OF_MEAS_NAME" );
178 *ppszUOMName = CPLStrdup( CSLGetField(papszUnitsRecord, iNameField) );
179 }
180
181 /* -------------------------------------------------------------------- */
182 /* Get the A and B factor fields, and create the multiplicative */
183 /* factor. */
184 /* -------------------------------------------------------------------- */
185 if( pdfInMeters != NULL )
186 {
187 int iBFactorField, iCFactorField;
188
189 iBFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_B" );
190 iCFactorField = CSVGetFileFieldId( UOM_FILENAME, "FACTOR_C" );
191
192 if( atof(CSLGetField(papszUnitsRecord, iCFactorField)) > 0.0 )
193 *pdfInMeters = atof(CSLGetField(papszUnitsRecord, iBFactorField))
194 / atof(CSLGetField(papszUnitsRecord, iCFactorField));
195 else
196 *pdfInMeters = 0.0;
197 }
198
199 return( TRUE );
200 }
201
202 /************************************************************************/
203 /* PCIGetEllipsoidInfo() */
204 /* */
205 /* Fetch info about an ellipsoid. Axes are always returned in */
206 /* meters. SemiMajor computed based on inverse flattening */
207 /* where that is provided. */
208 /************************************************************************/
209
210 static int
PCIGetEllipsoidInfo(int nCode,char ** ppszName,double * pdfSemiMajor,double * pdfInvFlattening)211 PCIGetEllipsoidInfo( int nCode, char ** ppszName,
212 double * pdfSemiMajor, double * pdfInvFlattening )
213
214 {
215 char szSearchKey[24];
216 double dfSemiMajor, dfToMeters = 1.0;
217 int nUOMLength;
218
219 /* -------------------------------------------------------------------- */
220 /* Get the semi major axis. */
221 /* -------------------------------------------------------------------- */
222 sprintf( szSearchKey, "%d", nCode );
223
224 dfSemiMajor =
225 atof(CSVGetField( CSVFilename("ellipsoid.csv" ),
226 "ELLIPSOID_CODE", szSearchKey, CC_Integer,
227 "SEMI_MAJOR_AXIS" ) );
228 if( dfSemiMajor == 0.0 )
229 return FALSE;
230
231 /* -------------------------------------------------------------------- */
232 /* Get the translation factor into meters. */
233 /* -------------------------------------------------------------------- */
234 nUOMLength = atoi(CSVGetField( CSVFilename("ellipsoid.csv" ),
235 "ELLIPSOID_CODE", szSearchKey, CC_Integer,
236 "UOM_CODE" ));
237 PCIGetUOMLengthInfo( nUOMLength, NULL, &dfToMeters );
238
239 dfSemiMajor *= dfToMeters;
240
241 if( pdfSemiMajor != NULL )
242 *pdfSemiMajor = dfSemiMajor;
243
244 /* -------------------------------------------------------------------- */
245 /* Get the semi-minor if requested. If the Semi-minor axis */
246 /* isn't available, compute it based on the inverse flattening. */
247 /* -------------------------------------------------------------------- */
248 if( pdfInvFlattening != NULL )
249 {
250 *pdfInvFlattening =
251 atof(CSVGetField( CSVFilename("ellipsoid.csv" ),
252 "ELLIPSOID_CODE", szSearchKey, CC_Integer,
253 "INV_FLATTENING" ));
254
255 if( *pdfInvFlattening == 0.0 )
256 {
257 double dfSemiMinor;
258
259 dfSemiMinor =
260 atof(CSVGetField( CSVFilename("ellipsoid.csv" ),
261 "ELLIPSOID_CODE", szSearchKey, CC_Integer,
262 "SEMI_MINOR_AXIS" )) * dfToMeters;
263
264 if( dfSemiMajor != 0.0 && dfSemiMajor != dfSemiMinor )
265 *pdfInvFlattening =
266 -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
267 else
268 *pdfInvFlattening = 0.0;
269 }
270 }
271
272 /* -------------------------------------------------------------------- */
273 /* Get the name, if requested. */
274 /* -------------------------------------------------------------------- */
275 if( ppszName != NULL )
276 *ppszName =
277 CPLStrdup(CSVGetField( CSVFilename("ellipsoid.csv" ),
278 "ELLIPSOID_CODE", szSearchKey, CC_Integer,
279 "ELLIPSOID_NAME" ));
280
281 return( TRUE );
282 }
283
284 /************************************************************************/
285 /* OSRImportFromPCI() */
286 /************************************************************************/
287
OSRImportFromPCI(OGRSpatialReferenceH hSRS,const char * pszProj,const char * pszUnits,double * padfPrjParams)288 OGRErr OSRImportFromPCI( OGRSpatialReferenceH hSRS, const char *pszProj,
289 const char *pszUnits, double *padfPrjParams )
290
291 {
292 VALIDATE_POINTER1( hSRS, "OSRImportFromPCI", CE_Failure );
293
294 return ((OGRSpatialReference *) hSRS)->importFromPCI( pszProj,
295 pszUnits,
296 padfPrjParams );
297 }
298
299 /************************************************************************/
300 /* importFromPCI() */
301 /************************************************************************/
302
303 /**
304 * Import coordinate system from PCI projection definition.
305 *
306 * PCI software uses 16-character string to specify coordinate system
307 * and datum/ellipsoid. You should supply at least this string to the
308 * importFromPCI() function.
309 *
310 * This function is the equilvelent of the C function OSRImportFromPCI().
311 *
312 * @param pszProj NULL terminated string containing the definition. Looks
313 * like "pppppppppppp Ennn" or "pppppppppppp Dnnn", where "pppppppppppp" is
314 * a projection code, "Ennn" is an ellipsoid code, "Dnnn" --- a datum code.
315 *
316 * @param pszUnits Grid units code ("DEGREE" or "METRE"). If NULL "METRE" will
317 * be used.
318 *
319 * @param padfPrjParams Array of 16 coordinate system parameters:
320 *
321 * [0] Spheroid semi major axis
322 * [1] Spheroid semi minor axis
323 * [2] Reference Longitude
324 * [3] Reference Latitude
325 * [4] First Standard Parallel
326 * [5] Second Standard Parallel
327 * [6] False Easting
328 * [7] False Northing
329 * [8] Scale Factor
330 * [9] Height above sphere surface
331 * [10] Longitude of 1st point on center line
332 * [11] Latitude of 1st point on center line
333 * [12] Longitude of 2nd point on center line
334 * [13] Latitude of 2nd point on center line
335 * [14] Azimuth east of north for center line
336 * [15] Landsat satellite number
337 * [16] Landsat path number
338 *
339 * Particular projection uses different parameters, unused ones may be set to
340 * zero. If NULL suppliet instead of array pointer default values will be
341 * used (i.e., zeroes).
342 *
343 * @return OGRERR_NONE on success or an error code in case of failure.
344 */
345
importFromPCI(const char * pszProj,const char * pszUnits,double * padfPrjParams)346 OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
347 const char *pszUnits,
348 double *padfPrjParams )
349
350 {
351 Clear();
352
353 if( pszProj == NULL )
354 return OGRERR_CORRUPT_DATA;
355
356 #ifdef DEBUG
357 CPLDebug( "OSR_PCI", "Trying to import projection \"%s\"", pszProj );
358 #endif
359
360 /* -------------------------------------------------------------------- */
361 /* Use safe defaults if projection parameters are not supplied. */
362 /* -------------------------------------------------------------------- */
363 int bProjAllocated = FALSE;
364
365 if( padfPrjParams == NULL )
366 {
367 int i;
368
369 padfPrjParams = (double *)CPLMalloc( 17 * sizeof(double) );
370 if ( !padfPrjParams )
371 return OGRERR_NOT_ENOUGH_MEMORY;
372 for ( i = 0; i < 17; i++ )
373 padfPrjParams[i] = 0.0;
374 bProjAllocated = TRUE;
375 }
376
377 /* -------------------------------------------------------------------- */
378 /* Operate on the basis of the projection name. */
379 /* -------------------------------------------------------------------- */
380 if( EQUALN( pszProj, "LONG/LAT", 8 ) )
381 {
382 }
383
384 else if( EQUALN( pszProj, "METER", 5 )
385 || EQUALN( pszProj, "METRE", 5 ) )
386 {
387 SetLocalCS( "METER" );
388 SetLinearUnits( "METER", 1.0 );
389 }
390
391 else if( EQUALN( pszProj, "FEET", 4 )
392 || EQUALN( pszProj, "FOOT", 4 ) )
393 {
394 SetLocalCS( "FEET" );
395 SetLinearUnits( "FEET", atof(SRS_UL_FOOT_CONV) );
396 }
397
398 else if( EQUALN( pszProj, "ACEA", 4 ) )
399 {
400 SetACEA( padfPrjParams[4], padfPrjParams[5],
401 padfPrjParams[3], padfPrjParams[2],
402 padfPrjParams[6], padfPrjParams[7] );
403 }
404
405 else if( EQUALN( pszProj, "AE", 2 ) )
406 {
407 SetAE( padfPrjParams[3], padfPrjParams[2],
408 padfPrjParams[6], padfPrjParams[7] );
409 }
410
411 else if( EQUALN( pszProj, "EC", 2 ) )
412 {
413 SetEC( padfPrjParams[4], padfPrjParams[5],
414 padfPrjParams[3], padfPrjParams[2],
415 padfPrjParams[6], padfPrjParams[7] );
416 }
417
418 else if( EQUALN( pszProj, "ER", 2 ) )
419 {
420 // PCI and GCTP don't support natural origin lat.
421 SetEquirectangular2( 0.0, padfPrjParams[2],
422 padfPrjParams[3],
423 padfPrjParams[6], padfPrjParams[7] );
424 }
425
426 else if( EQUALN( pszProj, "GNO", 3 ) )
427 {
428 SetGnomonic( padfPrjParams[3], padfPrjParams[2],
429 padfPrjParams[6], padfPrjParams[7] );
430 }
431
432 // FIXME: GVNP --- General Vertical Near- Side Perspective skipped
433
434 else if( EQUALN( pszProj, "LAEA", 4 ) )
435 {
436 SetLAEA( padfPrjParams[3], padfPrjParams[2],
437 padfPrjParams[6], padfPrjParams[7] );
438 }
439
440 else if( EQUALN( pszProj, "LCC", 3 ) )
441 {
442 SetLCC( padfPrjParams[4], padfPrjParams[5],
443 padfPrjParams[3], padfPrjParams[2],
444 padfPrjParams[6], padfPrjParams[7] );
445 }
446
447 else if( EQUALN( pszProj, "MC", 2 ) )
448 {
449 SetMC( padfPrjParams[3], padfPrjParams[2],
450 padfPrjParams[6], padfPrjParams[7] );
451 }
452
453 else if( EQUALN( pszProj, "MER", 3 ) )
454 {
455 SetMercator( padfPrjParams[3], padfPrjParams[2],
456 padfPrjParams[8],
457 padfPrjParams[6], padfPrjParams[7] );
458 }
459
460 else if( EQUALN( pszProj, "OG", 2 ) )
461 {
462 SetOrthographic( padfPrjParams[3], padfPrjParams[2],
463 padfPrjParams[6], padfPrjParams[7] );
464 }
465
466 // FIXME: OM --- Oblique Mercator skipped
467
468 else if( EQUALN( pszProj, "PC", 2 ) )
469 {
470 SetPolyconic( padfPrjParams[3], padfPrjParams[2],
471 padfPrjParams[6], padfPrjParams[7] );
472 }
473
474 else if( EQUALN( pszProj, "PS", 2 ) )
475 {
476 SetPS( padfPrjParams[3], padfPrjParams[2],
477 padfPrjParams[8],
478 padfPrjParams[6], padfPrjParams[7] );
479 }
480
481 else if( EQUALN( pszProj, "ROB", 3 ) )
482 {
483 SetRobinson( padfPrjParams[2],
484 padfPrjParams[6], padfPrjParams[7] );
485 }
486
487 else if( EQUALN( pszProj, "SG", 2 ) )
488 {
489 SetStereographic( padfPrjParams[3], padfPrjParams[2],
490 padfPrjParams[8],
491 padfPrjParams[6], padfPrjParams[7] );
492 }
493
494 else if( EQUALN( pszProj, "SIN", 3 ) )
495 {
496 SetSinusoidal( padfPrjParams[2],
497 padfPrjParams[6], padfPrjParams[7] );
498 }
499
500 // FIXME: SOM --- Space Oblique Mercator skipped
501
502 else if( EQUALN( pszProj, "SPCS", 4 ) )
503 {
504 int iZone, bNAD83 = TRUE;
505
506 iZone = CPLScanLong( (char *)pszProj + 5, 4 );
507
508 if ( !EQUALN( pszProj + 12, "E008", 4 ) )
509 bNAD83 = FALSE;
510
511 SetStatePlane( iZone, bNAD83 );
512 }
513
514 // FIXME: Add SPIF and SPAF? (state plane international or american feet)
515
516 else if( EQUALN( pszProj, "TM", 2 ) )
517 {
518 SetTM( padfPrjParams[3], padfPrjParams[2],
519 padfPrjParams[8],
520 padfPrjParams[6], padfPrjParams[7] );
521 }
522
523 else if( EQUALN( pszProj, "UTM", 3 ) )
524 {
525 int iZone, bNorth = TRUE;
526
527 iZone = CPLScanLong( (char *)pszProj + 4, 5 );;
528 if ( iZone < 0 )
529 {
530 iZone = -iZone;
531 bNorth = FALSE;
532 }
533
534 SetUTM( iZone, bNorth );
535 }
536
537 else if( EQUALN( pszProj, "VDG", 3 ) )
538 {
539 SetVDG( padfPrjParams[2],
540 padfPrjParams[6], padfPrjParams[7] );
541 }
542
543 else
544 {
545 CPLDebug( "OSR_PCI", "Unsupported projection: %s", pszProj );
546 SetLocalCS( pszProj );
547 }
548
549 /* ==================================================================== */
550 /* Translate the datum/spheroid. */
551 /* ==================================================================== */
552
553 /* -------------------------------------------------------------------- */
554 /* Extract and "normalize" the earthmodel to look like E001, */
555 /* D-02 or D109. */
556 /* -------------------------------------------------------------------- */
557 char szEarthModel[5];
558 const char *pszEM;
559
560 strcpy( szEarthModel, "" );
561 pszEM = pszProj + strlen(pszProj) - 1;
562 while( pszEM != pszProj )
563 {
564 if( *pszEM == 'e' || *pszEM == 'E' || *pszEM == 'd' || *pszEM == 'D' )
565 {
566 int nCode = atoi(pszEM+1);
567
568 if( nCode >= -99 && nCode <= 999 )
569 sprintf( szEarthModel, "%c%03d", toupper(*pszEM), nCode );
570
571 break;
572 }
573
574 pszEM--;
575 }
576
577 /* -------------------------------------------------------------------- */
578 /* We have an earthmodel string, look it up in the datum list. */
579 /* -------------------------------------------------------------------- */
580 if( strlen(szEarthModel) > 0
581 && (poRoot == NULL || IsProjected() || IsGeographic()) )
582 {
583 const PCIDatums *paoDatum = aoDatums;
584
585 // Search for matching datum
586 while ( paoDatum->pszPCIDatum )
587 {
588 if( EQUALN( szEarthModel, paoDatum->pszPCIDatum, 4 ) )
589 {
590 OGRSpatialReference oGCS;
591 oGCS.importFromEPSG( paoDatum->nEPSGCode );
592 CopyGeogCSFrom( &oGCS );
593 break;
594 }
595 paoDatum++;
596 }
597
598 /* -------------------------------------------------------------------- */
599 /* If not, look in the ellipsoid list. */
600 /* -------------------------------------------------------------------- */
601 if ( !paoDatum->pszPCIDatum ) // No matching; search for ellipsoids
602 {
603 paoDatum = aoEllips;
604
605 #ifdef DEBUG
606 CPLDebug( "OSR_PCI",
607 "Cannot found matching datum definition, "
608 "search for ellipsoids." );
609 #endif
610
611 while ( paoDatum->pszPCIDatum )
612 {
613 if( EQUALN( szEarthModel, paoDatum->pszPCIDatum, 4 )
614 && paoDatum->nEPSGCode != 0 )
615 {
616 char *pszName = NULL;
617 double dfSemiMajor;
618 double dfInvFlattening;
619
620 PCIGetEllipsoidInfo( paoDatum->nEPSGCode, &pszName,
621 &dfSemiMajor, &dfInvFlattening );
622 SetGeogCS( CPLString().Printf(
623 "Unknown datum based upon the %s ellipsoid",
624 pszName ),
625 CPLString().Printf(
626 "Not specified (based on %s spheroid)",
627 pszName ),
628 pszName, dfSemiMajor, dfInvFlattening,
629 NULL, 0.0, NULL, 0.0 );
630 SetAuthority( "SPHEROID", "EPSG", paoDatum->nEPSGCode );
631
632 if ( pszName )
633 CPLFree( pszName );
634
635 break;
636 }
637 else if( EQUALN( szEarthModel, paoDatum->pszPCIDatum, 4 ) )
638 {
639 double dfInvFlattening;
640
641 if( ABS(paoDatum->dfSemiMajor - paoDatum->dfSemiMinor)
642 < 0.01 )
643 dfInvFlattening = 0.0;
644 else
645 dfInvFlattening = paoDatum->dfSemiMajor
646 / (paoDatum->dfSemiMajor-paoDatum->dfSemiMinor);
647
648 SetGeogCS( "Unknown datum based upon the custom spheroid",
649 "Not specified (based on custom spheroid)",
650 CPLString().Printf( "PCI Ellipse %s",
651 szEarthModel),
652 paoDatum->dfSemiMajor, dfInvFlattening,
653 NULL, 0, NULL, 0 );
654 break;
655 }
656 paoDatum++;
657 }
658 }
659
660 /* -------------------------------------------------------------------- */
661 /* Custom spheroid. */
662 /* -------------------------------------------------------------------- */
663 if ( !paoDatum->pszPCIDatum ) // Didn't found matches
664 {
665 #ifdef DEBUG
666 CPLDebug( "OSR_PCI",
667 "Cannot found matching ellipsoid definition." );
668 #endif
669
670 if( EQUALN( pszProj + 12, "E999", 4 ) )
671 {
672 double dfInvFlattening;
673
674 if( ABS(padfPrjParams[0] - padfPrjParams[1]) < 0.01 )
675 {
676 dfInvFlattening = 0.0;
677 }
678 else
679 {
680 dfInvFlattening =
681 padfPrjParams[0]/(padfPrjParams[0]-padfPrjParams[1]);
682 }
683
684 SetGeogCS( "Unknown datum based upon the custom spheroid",
685 "Not specified (based on custom spheroid)",
686 "Custom spheroid",
687 padfPrjParams[0], dfInvFlattening,
688 NULL, 0, NULL, 0 );
689 }
690 else
691 {
692 // If we don't know, default to WGS84
693 // so there is something there.
694 SetWellKnownGeogCS( "WGS84" );
695 #ifdef DEBUG
696 CPLDebug( "OSR_PCI", "Setting WGS84 as a fallback." );
697 #endif
698
699 }
700 }
701 }
702
703 /* -------------------------------------------------------------------- */
704 /* Grid units translation */
705 /* -------------------------------------------------------------------- */
706 if( (IsLocal() || IsProjected()) && pszUnits )
707 {
708 if( EQUAL( pszUnits, "METRE" ) )
709 SetLinearUnits( SRS_UL_METER, 1.0 );
710 else if( EQUAL( pszUnits, "DEGREE" ) )
711 SetAngularUnits( SRS_UA_DEGREE, atof(SRS_UA_DEGREE_CONV) );
712 else
713 SetLinearUnits( SRS_UL_METER, 1.0 );
714 }
715
716 FixupOrdering();
717
718 if ( bProjAllocated && padfPrjParams )
719 CPLFree( padfPrjParams );
720
721 return OGRERR_NONE;
722 }
723
724 /************************************************************************/
725 /* OSRExportToPCI() */
726 /************************************************************************/
727
OSRExportToPCI(OGRSpatialReferenceH hSRS,char ** ppszProj,char ** ppszUnits,double ** ppadfPrjParams)728 OGRErr OSRExportToPCI( OGRSpatialReferenceH hSRS,
729 char **ppszProj, char **ppszUnits,
730 double **ppadfPrjParams )
731
732 {
733 VALIDATE_POINTER1( hSRS, "OSRExportToPCI", CE_Failure );
734
735 *ppszProj = NULL;
736 *ppszUnits = NULL;
737 *ppadfPrjParams = NULL;
738
739 return ((OGRSpatialReference *) hSRS)->exportToPCI( ppszProj, ppszUnits,
740 ppadfPrjParams );
741 }
742
743 /************************************************************************/
744 /* exportToPCI() */
745 /************************************************************************/
746
747 /**
748 * Export coordinate system in PCI projection definition.
749 *
750 * Converts the loaded coordinate reference system into PCI projection
751 * definition to the extent possible. The strings returned in ppszProj,
752 * ppszUnits and ppadfPrjParams array should be deallocated by the caller
753 * with CPLFree() when no longer needed.
754 *
755 * LOCAL_CS coordinate systems are not translatable. An empty string
756 * will be returned along with OGRERR_NONE.
757 *
758 * This method is the equivelent of the C function OSRExportToPCI().
759 *
760 * @param ppszProj pointer to which dynamically allocated PCI projection
761 * definition will be assigned.
762 *
763 * @param ppszUnits pointer to which dynamically allocated units definition
764 * will be assigned.
765 *
766 * @param ppadfPrjParams pointer to which dynamically allocated array of
767 * 17 projection parameters will be assigned. See importFromPCI() for the list
768 * of parameters.
769 *
770 * @return OGRERR_NONE on success or an error code on failure.
771 */
772
exportToPCI(char ** ppszProj,char ** ppszUnits,double ** ppadfPrjParams) const773 OGRErr OGRSpatialReference::exportToPCI( char **ppszProj, char **ppszUnits,
774 double **ppadfPrjParams ) const
775
776 {
777 const char *pszProjection = GetAttrValue("PROJECTION");
778
779 /* -------------------------------------------------------------------- */
780 /* Fill all projection parameters with zero. */
781 /* -------------------------------------------------------------------- */
782 int i;
783
784 *ppadfPrjParams = (double *)CPLMalloc( 17 * sizeof(double) );
785 for ( i = 0; i < 17; i++ )
786 (*ppadfPrjParams)[i] = 0.0;
787
788 /* -------------------------------------------------------------------- */
789 /* Get the prime meridian info. */
790 /* -------------------------------------------------------------------- */
791 const OGR_SRSNode *poPRIMEM = GetAttrNode( "PRIMEM" );
792 double dfFromGreenwich = 0.0;
793
794 if( poPRIMEM != NULL && poPRIMEM->GetChildCount() >= 2
795 && atof(poPRIMEM->GetChild(1)->GetValue()) != 0.0 )
796 {
797 dfFromGreenwich = atof(poPRIMEM->GetChild(1)->GetValue());
798 }
799
800 /* ==================================================================== */
801 /* Handle the projection definition. */
802 /* ==================================================================== */
803 char szProj[17];
804
805 if( IsLocal() )
806 {
807 if( GetLinearUnits() > 0.30479999 && GetLinearUnits() < 0.3048010 )
808 CPLPrintStringFill( szProj, "FEET", 17 );
809 else
810 CPLPrintStringFill( szProj, "METER", 17 );
811 }
812
813 else if( pszProjection == NULL )
814 {
815 #ifdef DEBUG
816 CPLDebug( "OSR_PCI",
817 "Empty projection definition, considered as LONG/LAT" );
818 #endif
819 CPLPrintStringFill( szProj, "LONG/LAT", 17 );
820 }
821
822 else if( EQUAL(pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
823 {
824 CPLPrintStringFill( szProj, "ACEA", 16 );
825 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
826 (*ppadfPrjParams)[3] =
827 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
828 (*ppadfPrjParams)[4] =
829 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 );
830 (*ppadfPrjParams)[5] =
831 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_2, 0.0 );
832 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
833 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
834 }
835
836 else if( EQUAL(pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT) )
837 {
838 CPLPrintStringFill( szProj, "AE", 16 );
839 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
840 (*ppadfPrjParams)[3] =
841 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
842 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
843 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
844 }
845
846 else if( EQUAL(pszProjection, SRS_PT_EQUIDISTANT_CONIC) )
847 {
848 CPLPrintStringFill( szProj, "EC", 16 );
849 (*ppadfPrjParams)[2] =
850 GetNormProjParm( SRS_PP_LONGITUDE_OF_CENTER, 0.0 );
851 (*ppadfPrjParams)[3] =
852 GetNormProjParm( SRS_PP_LATITUDE_OF_CENTER, 0.0 );
853 (*ppadfPrjParams)[4] =
854 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 );
855 (*ppadfPrjParams)[5] =
856 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_2, 0.0 );
857 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
858 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
859 }
860
861 else if( EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR) )
862 {
863 CPLPrintStringFill( szProj, "ER", 16 );
864 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
865 (*ppadfPrjParams)[3] =
866 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 );
867 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
868 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
869 }
870
871 else if( EQUAL(pszProjection, SRS_PT_GNOMONIC) )
872 {
873 CPLPrintStringFill( szProj, "GNO", 16 );
874 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
875 (*ppadfPrjParams)[3] =
876 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
877 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
878 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
879 }
880
881 else if( EQUAL(pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
882 {
883 CPLPrintStringFill( szProj, "LAEA", 16 );
884 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
885 (*ppadfPrjParams)[3] =
886 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
887 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
888 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
889 }
890
891 else if( EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) )
892 {
893 CPLPrintStringFill( szProj, "LCC", 16 );
894 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
895 (*ppadfPrjParams)[3] =
896 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
897 (*ppadfPrjParams)[4] =
898 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 );
899 (*ppadfPrjParams)[5] =
900 GetNormProjParm( SRS_PP_STANDARD_PARALLEL_2, 0.0 );
901 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
902 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
903 }
904
905 else if( EQUAL(pszProjection, SRS_PT_MILLER_CYLINDRICAL) )
906 {
907 CPLPrintStringFill( szProj, "MC", 16 );
908 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
909 (*ppadfPrjParams)[3] =
910 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
911 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
912 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
913 }
914
915 else if( EQUAL(pszProjection, SRS_PT_MERCATOR_1SP) )
916 {
917 CPLPrintStringFill( szProj, "MER", 16 );
918 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
919 (*ppadfPrjParams)[3] =
920 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
921 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
922 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
923 (*ppadfPrjParams)[8] = GetNormProjParm( SRS_PP_SCALE_FACTOR, 1.0 );
924 }
925
926 else if( EQUAL(pszProjection, SRS_PT_ORTHOGRAPHIC) )
927 {
928 CPLPrintStringFill( szProj, "OG", 16 );
929 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
930 (*ppadfPrjParams)[3] =
931 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
932 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
933 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
934 }
935
936 else if( EQUAL(pszProjection, SRS_PT_POLYCONIC) )
937 {
938 CPLPrintStringFill( szProj, "PC", 16 );
939 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
940 (*ppadfPrjParams)[3] =
941 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
942 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
943 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
944 }
945
946 else if( EQUAL(pszProjection, SRS_PT_POLAR_STEREOGRAPHIC) )
947 {
948 CPLPrintStringFill( szProj, "PS", 16 );
949 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
950 (*ppadfPrjParams)[3] =
951 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
952 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
953 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
954 (*ppadfPrjParams)[8] = GetNormProjParm( SRS_PP_SCALE_FACTOR, 1.0 );
955 }
956
957 else if( EQUAL(pszProjection, SRS_PT_ROBINSON) )
958 {
959 CPLPrintStringFill( szProj, "ROB", 16 );
960 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
961 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
962 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
963 }
964
965 else if( EQUAL(pszProjection, SRS_PT_STEREOGRAPHIC) )
966 {
967 CPLPrintStringFill( szProj, "SG", 16 );
968 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
969 (*ppadfPrjParams)[3] =
970 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
971 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
972 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
973 (*ppadfPrjParams)[8] = GetNormProjParm( SRS_PP_SCALE_FACTOR, 1.0 );
974 }
975
976 else if( EQUAL(pszProjection, SRS_PT_SINUSOIDAL) )
977 {
978 CPLPrintStringFill( szProj, "SIN", 16 );
979 (*ppadfPrjParams)[2] =
980 GetNormProjParm( SRS_PP_LONGITUDE_OF_CENTER, 0.0 );
981 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
982 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
983 }
984
985 else if( EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR) )
986 {
987 int bNorth;
988 int nZone = GetUTMZone( &bNorth );
989
990 if( nZone != 0 )
991 {
992 CPLPrintStringFill( szProj, "UTM", 16 );
993 if( bNorth )
994 CPLPrintInt32( szProj + 5, nZone, 4 );
995 else
996 CPLPrintInt32( szProj + 5, -nZone, 4 );
997 }
998 else
999 {
1000 CPLPrintStringFill( szProj, "TM", 16 );
1001 (*ppadfPrjParams)[2] =
1002 GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
1003 (*ppadfPrjParams)[3] =
1004 GetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, 0.0 );
1005 (*ppadfPrjParams)[6] = GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0);
1006 (*ppadfPrjParams)[7] = GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0);
1007 (*ppadfPrjParams)[8] = GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0);
1008 }
1009 }
1010
1011 else if( EQUAL(pszProjection, SRS_PT_VANDERGRINTEN) )
1012 {
1013 CPLPrintStringFill( szProj, "VDG", 16 );
1014 (*ppadfPrjParams)[2] = GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 );
1015 (*ppadfPrjParams)[6] = GetNormProjParm( SRS_PP_FALSE_EASTING, 0.0 );
1016 (*ppadfPrjParams)[7] = GetNormProjParm( SRS_PP_FALSE_NORTHING, 0.0 );
1017 }
1018
1019 // Projection unsupported by PCI
1020 else
1021 {
1022 CPLDebug( "OSR_PCI",
1023 "Projection \"%s\" unsupported by PCI. "
1024 "PIXEL value will be used.", pszProjection );
1025 CPLPrintStringFill( szProj, "PIXEL", 16 );
1026 }
1027
1028 /* -------------------------------------------------------------------- */
1029 /* Translate the datum. */
1030 /* -------------------------------------------------------------------- */
1031 const char *pszDatum = GetAttrValue( "DATUM" );
1032
1033 if( pszDatum == NULL || strlen(pszDatum) == 0 )
1034 /* do nothing */;
1035 else if( EQUAL( pszDatum, SRS_DN_NAD27 ) )
1036 CPLPrintStringFill( szProj + 12, "D-01", 4 );
1037
1038 else if( EQUAL( pszDatum, SRS_DN_NAD83 ) )
1039 CPLPrintStringFill( szProj + 12, "D-02", 4 );
1040
1041 else if( EQUAL( pszDatum, SRS_DN_WGS84 ) )
1042 CPLPrintStringFill( szProj + 12, "D000", 4 );
1043
1044 // If not found well known datum, translate ellipsoid
1045 else
1046 {
1047 double dfSemiMajor = GetSemiMajor();
1048 double dfInvFlattening = GetInvFlattening();
1049
1050 const PCIDatums *paoDatum = aoEllips;
1051
1052 #ifdef DEBUG
1053 CPLDebug( "OSR_PCI",
1054 "Datum \"%s\" unsupported by PCI. "
1055 "Try to translate ellipsoid definition.", pszDatum );
1056 #endif
1057
1058 while ( paoDatum->pszPCIDatum )
1059 {
1060 double dfSM;
1061 double dfIF;
1062
1063 PCIGetEllipsoidInfo( paoDatum->nEPSGCode, NULL, &dfSM, &dfIF );
1064 if( ABS( dfSemiMajor - dfSM ) < 0.01
1065 && ABS( dfInvFlattening - dfIF ) < 0.0001 )
1066 {
1067 CPLPrintStringFill( szProj + 12, paoDatum->pszPCIDatum, 4 );
1068 break;
1069 }
1070
1071 paoDatum++;
1072 }
1073
1074 if ( !paoDatum->pszPCIDatum ) // Didn't found matches; set
1075 { // custom ellipsoid parameters
1076 #ifdef DEBUG
1077 CPLDebug( "OSR_PCI",
1078 "Ellipsoid \"%s\" unsupported by PCI. "
1079 "Custom PCI ellipsoid will be used.", pszDatum );
1080 #endif
1081 CPLPrintStringFill( szProj + 12, "E999", 4 );
1082 (*ppadfPrjParams)[0] = dfSemiMajor;
1083 if ( ABS( dfInvFlattening ) < 0.000000000001 )
1084 {
1085 (*ppadfPrjParams)[1] = dfSemiMajor;
1086 }
1087 else
1088 {
1089 (*ppadfPrjParams)[1] =
1090 dfSemiMajor * (1.0 - 1.0/dfInvFlattening);
1091 }
1092 }
1093 }
1094
1095 /* -------------------------------------------------------------------- */
1096 /* Translate the linear units. */
1097 /* -------------------------------------------------------------------- */
1098 const char *pszUnits;
1099
1100 if( EQUALN( szProj, "LONG/LAT", 8 ) )
1101 pszUnits = "DEGREE";
1102 else
1103 pszUnits = "METRE";
1104
1105 /* -------------------------------------------------------------------- */
1106 /* Report results. */
1107 /* -------------------------------------------------------------------- */
1108 szProj[16] = '\0';
1109 *ppszProj = CPLStrdup( szProj );
1110
1111 *ppszUnits = CPLStrdup( pszUnits );
1112
1113 return OGRERR_NONE;
1114 }
1115
1116