Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GXF Reader
4 : * Purpose: Handle GXF to OGC WKT projection transformation.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Frank Warmerdam
9 : * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "gxfopen.h"
15 : #include "ogr_srs_api.h"
16 :
17 : /* -------------------------------------------------------------------- */
18 : /* the following #defines come from ogr_spatialref.h in the GDAL/OGR */
19 : /* distribution (see http://gdal.velocet.ca/projects/opengis) and */
20 : /* should be kept in sync with that file. */
21 : /* -------------------------------------------------------------------- */
22 :
23 : #define SRS_PT_ALBERS_CONIC_EQUAL_AREA "Albers_Conic_Equal_Area"
24 : #define SRS_PT_AZIMUTHAL_EQUIDISTANT "Azimuthal_Equidistant"
25 : #define SRS_PT_CASSINI_SOLDNER "Cassini_Soldner"
26 : #define SRS_PT_CYLINDRICAL_EQUAL_AREA "Cylindrical_Equal_Area"
27 : #define SRS_PT_ECKERT_IV "Eckert_IV"
28 : #define SRS_PT_ECKERT_VI "Eckert_VI"
29 : #define SRS_PT_EQUIDISTANT_CONIC "Equidistant_Conic"
30 : #define SRS_PT_EQUIRECTANGULAR "Equirectangular"
31 : #define SRS_PT_GALL_STEREOGRAPHIC "Gall_Stereographic"
32 : #define SRS_PT_GNOMONIC "Gnomonic"
33 : #define SRS_PT_HOTINE_OBLIQUE_MERCATOR "Hotine_Oblique_Mercator"
34 : #define SRS_PT_LABORDE_OBLIQUE_MERCATOR "Laborde_Oblique_Mercator"
35 : #define SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP "Lambert_Conformal_Conic_1SP"
36 : #define SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP "Lambert_Conformal_Conic_2SP"
37 : #define SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM \
38 : "Lambert_Conformal_Conic_2SP_Belgium"
39 : #define SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA "Lambert_Azimuthal_Equal_Area"
40 : #define SRS_PT_MERCATOR_1SP "Mercator_1SP"
41 : #define SRS_PT_MERCATOR_2SP "Mercator_2SP"
42 : #define SRS_PT_MILLER_CYLINDRICAL "Miller_Cylindrical"
43 : #define SRS_PT_MOLLWEIDE "Mollweide"
44 : #define SRS_PT_NEW_ZEALAND_MAP_GRID "New_Zealand_Map_Grid"
45 : #define SRS_PT_OBLIQUE_STEREOGRAPHIC "Oblique_Stereographic"
46 : #define SRS_PT_ORTHOGRAPHIC "Orthographic"
47 : #define SRS_PT_POLAR_STEREOGRAPHIC "Polar_Stereographic"
48 : #define SRS_PT_POLYCONIC "Polyconic"
49 : #define SRS_PT_ROBINSON "Robinson"
50 : #define SRS_PT_SINUSOIDAL "Sinusoidal"
51 : #define SRS_PT_STEREOGRAPHIC "Stereographic"
52 : #define SRS_PT_SWISS_OBLIQUE_CYLINDRICAL "Swiss_Oblique_Cylindrical"
53 : #define SRS_PT_TRANSVERSE_MERCATOR "Transverse_Mercator"
54 : #define SRS_PT_TRANSVERSE_MERCATOR_SOUTH_ORIENTED \
55 : "Transverse_Mercator_South_Orientated"
56 : #define SRS_PT_TUNISIA_MINING_GRID "Tunisia_Mining_Grid"
57 : #define SRS_PT_VANDERGRINTEN "VanDerGrinten"
58 :
59 : #define SRS_PP_CENTRAL_MERIDIAN "central_meridian"
60 : #define SRS_PP_SCALE_FACTOR "scale_factor"
61 : #define SRS_PP_STANDARD_PARALLEL_1 "standard_parallel_1"
62 : #define SRS_PP_STANDARD_PARALLEL_2 "standard_parallel_2"
63 : #define SRS_PP_LONGITUDE_OF_CENTER "longitude_of_center"
64 : #define SRS_PP_LATITUDE_OF_CENTER "latitude_of_center"
65 : #define SRS_PP_LONGITUDE_OF_ORIGIN "longitude_of_origin"
66 : #define SRS_PP_LATITUDE_OF_ORIGIN "latitude_of_origin"
67 : #define SRS_PP_FALSE_EASTING "false_easting"
68 : #define SRS_PP_FALSE_NORTHING "false_northing"
69 : #define SRS_PP_AZIMUTH "azimuth"
70 : #define SRS_PP_LONGITUDE_OF_POINT_1 "longitude_of_point_1"
71 : #define SRS_PP_LATITUDE_OF_POINT_1 "latitude_of_point_1"
72 : #define SRS_PP_LONGITUDE_OF_POINT_2 "longitude_of_point_2"
73 : #define SRS_PP_LATITUDE_OF_POINT_2 "latitude_of_point_2"
74 : #define SRS_PP_LONGITUDE_OF_POINT_3 "longitude_of_point_3"
75 : #define SRS_PP_LATITUDE_OF_POINT_3 "latitude_of_point_3"
76 : #define SRS_PP_RECTIFIED_GRID_ANGLE "rectified_grid_angle"
77 :
78 : /* -------------------------------------------------------------------- */
79 : /* This table was copied from gt_wkt_srs.cpp in the libgeotiff */
80 : /* distribution. Please keep changes in sync. */
81 : /* -------------------------------------------------------------------- */
82 : static const char *const papszDatumEquiv[] = {
83 : "Militar_Geographische_Institut",
84 : "Militar_Geographische_Institute",
85 : "World_Geodetic_System_1984",
86 : "WGS_1984",
87 : "WGS_72_Transit_Broadcast_Ephemeris",
88 : "WGS_1972_Transit_Broadcast_Ephemeris",
89 : "World_Geodetic_System_1972",
90 : "WGS_1972",
91 : "European_Terrestrial_Reference_System_89",
92 : "European_Reference_System_1989",
93 : NULL};
94 :
95 : /************************************************************************/
96 : /* WKTMassageDatum() */
97 : /* */
98 : /* Massage an EPSG datum name into WMT format. Also transform */
99 : /* specific exception cases into WKT versions. */
100 : /* */
101 : /* This function was copied from the gt_wkt_srs.cpp file in the */
102 : /* libgeotiff distribution. Please keep changes in sync. */
103 : /************************************************************************/
104 :
105 2 : static void WKTMassageDatum(char **ppszDatum)
106 :
107 : {
108 : int i, j;
109 : char *pszDatum;
110 :
111 2 : pszDatum = *ppszDatum;
112 2 : if (pszDatum[0] == '\0')
113 0 : return;
114 :
115 : /* -------------------------------------------------------------------- */
116 : /* Translate non-alphanumeric values to underscores. */
117 : /* -------------------------------------------------------------------- */
118 12 : for (i = 0; pszDatum[i] != '\0'; i++)
119 : {
120 10 : if (pszDatum[i] != '+' && !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z') &&
121 4 : !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z') &&
122 4 : !(pszDatum[i] >= '0' && pszDatum[i] <= '9'))
123 : {
124 0 : pszDatum[i] = '_';
125 : }
126 : }
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Remove repeated and trailing underscores. */
130 : /* -------------------------------------------------------------------- */
131 10 : for (i = 1, j = 0; pszDatum[i] != '\0'; i++)
132 : {
133 8 : if (pszDatum[j] == '_' && pszDatum[i] == '_')
134 0 : continue;
135 :
136 8 : pszDatum[++j] = pszDatum[i];
137 : }
138 2 : if (pszDatum[j] == '_')
139 0 : pszDatum[j] = '\0';
140 : else
141 2 : pszDatum[j + 1] = '\0';
142 :
143 : /* -------------------------------------------------------------------- */
144 : /* Search for datum equivalences. Specific massaged names get */
145 : /* mapped to OpenGIS specified names. */
146 : /* -------------------------------------------------------------------- */
147 12 : for (i = 0; papszDatumEquiv[i] != NULL; i += 2)
148 : {
149 10 : if (EQUAL(*ppszDatum, papszDatumEquiv[i]))
150 : {
151 0 : CPLFree(*ppszDatum);
152 0 : *ppszDatum = CPLStrdup(papszDatumEquiv[i + 1]);
153 0 : return;
154 : }
155 : }
156 : }
157 :
158 : /************************************************************************/
159 : /* OGCWKTSetProj() */
160 : /************************************************************************/
161 :
162 2 : static void OGCWKTSetProj(char *pszProjection, size_t nProjectionSize,
163 : char **papszMethods, const char *pszTransformName,
164 : const char *pszParm1, const char *pszParm2,
165 : const char *pszParm3, const char *pszParm4,
166 : const char *pszParm5, const char *pszParm6,
167 : const char *pszParm7)
168 :
169 : {
170 2 : int iParam, nCount = CSLCount(papszMethods);
171 2 : const char *apszParamNames[8] = {NULL};
172 :
173 2 : apszParamNames[0] = pszParm1;
174 2 : apszParamNames[1] = pszParm2;
175 2 : apszParamNames[2] = pszParm3;
176 2 : apszParamNames[3] = pszParm4;
177 2 : apszParamNames[4] = pszParm5;
178 2 : apszParamNames[5] = pszParm6;
179 2 : apszParamNames[6] = pszParm7;
180 2 : apszParamNames[7] = NULL;
181 :
182 2 : snprintf(pszProjection, nProjectionSize, "PROJECTION[\"%s\"]",
183 : pszTransformName);
184 :
185 12 : for (iParam = 0; iParam < nCount - 1 && apszParamNames[iParam] != NULL;
186 10 : iParam++)
187 : {
188 10 : snprintf(pszProjection + strlen(pszProjection),
189 10 : nProjectionSize - strlen(pszProjection),
190 : ",PARAMETER[\"%s\",%s]", apszParamNames[iParam],
191 10 : papszMethods[iParam + 1]);
192 : }
193 2 : }
194 :
195 : /************************************************************************/
196 : /* GXFGetMapProjectionAsOGCWKT() */
197 : /************************************************************************/
198 :
199 : /**
200 : * Return the GXF Projection in OpenGIS Well Known Text format.
201 : *
202 : * The returned string becomes owned by the caller, and should be freed
203 : * with CPLFree() or VSIFree(). The return value will be "" if
204 : * no projection information is passed.
205 : *
206 : * The mapping of GXF projections to OGC WKT format is not complete. Please
207 : * see the gxf_ogcwkt.c code to better understand limitations of this
208 : * translation. More information about OGC WKT format can be found in
209 : * the OpenGIS Simple Features specification for OLEDB/COM found on the
210 : * OpenGIS web site at <a href="http://www.opengis.org/">www.opengis.org</a>.
211 : * The translation uses some code cribbed from the OGR library, about which
212 : * more can be learned from <a href="http://gdal.velocet.ca/projects/opengis/">
213 : * http://gdal.velocet.ca/projects/opengis/</a>.
214 : *
215 : * For example, the following GXF definitions:
216 : * <pre>
217 : * #UNIT_LENGTH
218 : * m,1
219 : * #MAP_PROJECTION
220 : * "NAD83 / UTM zone 19N"
221 : * "GRS 1980",6378137,0.081819191,0
222 : * "Transverse Mercator",0,-69,0.9996,500000,0
223 : * </pre>
224 : *
225 : * Would translate to (without the nice formatting):
226 : * <pre>
227 : PROJCS["NAD83 / UTM zone 19N",
228 : GEOGCS["GRS 1980",
229 : DATUM["GRS_1980",
230 : SPHEROID["GRS 1980",6378137,298.257222413684]],
231 : PRIMEM["unnamed",0],
232 : UNIT["degree",0.0174532925199433]],
233 : PROJECTION["Transverse_Mercator"],
234 : PARAMETER["latitude_of_origin",0],
235 : PARAMETER["central_meridian",-69],
236 : PARAMETER["scale_factor",0.9996],
237 : PARAMETER["false_easting",500000],
238 : PARAMETER["false_northing",0],
239 : UNIT["m",1]]
240 : * </pre>
241 : *
242 : * @param hGXF handle to GXF file, as returned by GXFOpen().
243 : *
244 : * @return string containing OGC WKT projection.
245 : */
246 :
247 4 : char *GXFGetMapProjectionAsOGCWKT(GXFHandle hGXF)
248 :
249 : {
250 4 : GXFInfo_t *psGXF = hGXF;
251 4 : char **papszMethods = NULL;
252 : char szWKT[1024 + 32];
253 : char szGCS[512];
254 : char szProjection[512];
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* If there was nothing in the file return "unknown". */
258 : /* -------------------------------------------------------------------- */
259 4 : if (CSLCount(psGXF->papszMapProjection) < 2)
260 2 : return (CPLStrdup(""));
261 :
262 2 : strcpy(szWKT, "");
263 2 : strcpy(szGCS, "");
264 2 : strcpy(szProjection, "");
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Parse the third line, looking for known projection methods. */
268 : /* -------------------------------------------------------------------- */
269 2 : if (psGXF->papszMapProjection[2] != NULL)
270 : {
271 : /* We allow more than 80 characters if the projection parameters */
272 : /* are on 2 lines as allowed by GXF 3 */
273 2 : if (strlen(psGXF->papszMapProjection[2]) > 120)
274 0 : return (CPLStrdup(""));
275 2 : papszMethods = CSLTokenizeStringComplex(psGXF->papszMapProjection[2],
276 : ",", TRUE, TRUE);
277 : }
278 :
279 : /* -------------------------------------------------------------------- */
280 : /* Create the PROJCS. */
281 : /* -------------------------------------------------------------------- */
282 2 : if (papszMethods == NULL || papszMethods[0] == NULL ||
283 2 : EQUAL(papszMethods[0], "Geographic"))
284 : {
285 : /* do nothing */
286 : }
287 :
288 2 : else if (EQUAL(papszMethods[0], "Lambert Conic Conformal (1SP)"))
289 : {
290 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
291 : SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP,
292 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_CENTRAL_MERIDIAN,
293 : SRS_PP_SCALE_FACTOR, SRS_PP_FALSE_EASTING,
294 : SRS_PP_FALSE_NORTHING, NULL, NULL);
295 : }
296 :
297 2 : else if (EQUAL(papszMethods[0], "Lambert Conic Conformal (2SP)"))
298 : {
299 2 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
300 : SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP,
301 : SRS_PP_STANDARD_PARALLEL_1, SRS_PP_STANDARD_PARALLEL_2,
302 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_CENTRAL_MERIDIAN,
303 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL);
304 : }
305 :
306 0 : else if (EQUAL(papszMethods[0], "Lambert Conformal (2SP Belgium)"))
307 : {
308 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
309 : SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM,
310 : SRS_PP_STANDARD_PARALLEL_1, SRS_PP_STANDARD_PARALLEL_2,
311 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_CENTRAL_MERIDIAN,
312 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL);
313 : }
314 :
315 0 : else if (EQUAL(papszMethods[0], "Mercator (1SP)"))
316 : {
317 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
318 : SRS_PT_MERCATOR_1SP, SRS_PP_LATITUDE_OF_ORIGIN,
319 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_SCALE_FACTOR,
320 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL);
321 : }
322 :
323 0 : else if (EQUAL(papszMethods[0], "Mercator (2SP)"))
324 : {
325 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
326 : SRS_PT_MERCATOR_2SP,
327 : SRS_PP_LATITUDE_OF_ORIGIN, /* should it be StdParalle1?*/
328 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_FALSE_EASTING,
329 : SRS_PP_FALSE_NORTHING, NULL, NULL, NULL);
330 : }
331 :
332 0 : else if (EQUAL(papszMethods[0], "Laborde Oblique Mercator"))
333 : {
334 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
335 : SRS_PT_LABORDE_OBLIQUE_MERCATOR,
336 : SRS_PP_LATITUDE_OF_CENTER, SRS_PP_LONGITUDE_OF_CENTER,
337 : SRS_PP_AZIMUTH, SRS_PP_SCALE_FACTOR, SRS_PP_FALSE_EASTING,
338 : SRS_PP_FALSE_NORTHING, NULL);
339 : }
340 :
341 0 : else if (EQUAL(papszMethods[0], "Hotine Oblique Mercator"))
342 : {
343 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
344 : SRS_PT_HOTINE_OBLIQUE_MERCATOR, SRS_PP_LATITUDE_OF_CENTER,
345 : SRS_PP_LONGITUDE_OF_CENTER, SRS_PP_AZIMUTH,
346 : SRS_PP_RECTIFIED_GRID_ANGLE,
347 : SRS_PP_SCALE_FACTOR, /* not in normal formulation */
348 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING);
349 : }
350 :
351 0 : else if (EQUAL(papszMethods[0], "New Zealand Map Grid"))
352 :
353 : {
354 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
355 : SRS_PT_NEW_ZEALAND_MAP_GRID, SRS_PP_LATITUDE_OF_ORIGIN,
356 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_FALSE_EASTING,
357 : SRS_PP_FALSE_NORTHING, NULL, NULL, NULL);
358 : }
359 :
360 0 : else if (EQUAL(papszMethods[0], "Oblique Stereographic"))
361 : {
362 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
363 : SRS_PT_OBLIQUE_STEREOGRAPHIC, SRS_PP_LATITUDE_OF_ORIGIN,
364 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_SCALE_FACTOR,
365 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL);
366 : }
367 :
368 0 : else if (EQUAL(papszMethods[0], "Polar Stereographic"))
369 : {
370 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
371 : SRS_PT_POLAR_STEREOGRAPHIC, SRS_PP_LATITUDE_OF_ORIGIN,
372 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_SCALE_FACTOR,
373 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL);
374 : }
375 :
376 0 : else if (EQUAL(papszMethods[0], "Swiss Oblique Cylindrical"))
377 : {
378 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
379 : SRS_PT_SWISS_OBLIQUE_CYLINDRICAL,
380 : SRS_PP_LATITUDE_OF_CENTER, SRS_PP_LONGITUDE_OF_CENTER,
381 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL,
382 : NULL);
383 : }
384 :
385 0 : else if (EQUAL(papszMethods[0], "Transverse Mercator"))
386 : {
387 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
388 : SRS_PT_TRANSVERSE_MERCATOR, SRS_PP_LATITUDE_OF_ORIGIN,
389 : SRS_PP_CENTRAL_MERIDIAN, SRS_PP_SCALE_FACTOR,
390 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL);
391 : }
392 :
393 0 : else if (EQUAL(papszMethods[0], "Transverse Mercator (South Oriented)") ||
394 0 : EQUAL(papszMethods[0], "Transverse Mercator (South Orientated)"))
395 : {
396 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
397 : SRS_PT_TRANSVERSE_MERCATOR_SOUTH_ORIENTED,
398 : SRS_PP_LATITUDE_OF_ORIGIN, SRS_PP_CENTRAL_MERIDIAN,
399 : SRS_PP_SCALE_FACTOR, SRS_PP_FALSE_EASTING,
400 : SRS_PP_FALSE_NORTHING, NULL, NULL);
401 : }
402 :
403 0 : else if (EQUAL(papszMethods[0], "*Albers Conic"))
404 : {
405 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
406 : SRS_PT_ALBERS_CONIC_EQUAL_AREA,
407 : SRS_PP_STANDARD_PARALLEL_1, SRS_PP_STANDARD_PARALLEL_2,
408 : SRS_PP_LATITUDE_OF_CENTER, SRS_PP_LONGITUDE_OF_CENTER,
409 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL);
410 : }
411 :
412 0 : else if (EQUAL(papszMethods[0], "*Equidistant Conic"))
413 : {
414 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
415 : SRS_PT_EQUIDISTANT_CONIC, SRS_PP_STANDARD_PARALLEL_1,
416 : SRS_PP_STANDARD_PARALLEL_2, SRS_PP_LATITUDE_OF_CENTER,
417 : SRS_PP_LONGITUDE_OF_CENTER, SRS_PP_FALSE_EASTING,
418 : SRS_PP_FALSE_NORTHING, NULL);
419 : }
420 :
421 0 : else if (EQUAL(papszMethods[0], "*Polyconic"))
422 : {
423 0 : OGCWKTSetProj(szProjection, sizeof(szProjection), papszMethods,
424 : SRS_PT_POLYCONIC, SRS_PP_LATITUDE_OF_ORIGIN,
425 : SRS_PP_CENTRAL_MERIDIAN,
426 : SRS_PP_SCALE_FACTOR, /* not normally expected */
427 : SRS_PP_FALSE_EASTING, SRS_PP_FALSE_NORTHING, NULL, NULL);
428 : }
429 :
430 2 : CSLDestroy(papszMethods);
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Extract the linear Units specification. */
434 : /* -------------------------------------------------------------------- */
435 2 : if (psGXF->pszUnitName != NULL && strlen(szProjection) > 0)
436 : {
437 2 : if (strlen(psGXF->pszUnitName) > 80)
438 0 : return CPLStrdup("");
439 :
440 2 : CPLsnprintf(szProjection + strlen(szProjection),
441 2 : sizeof(szProjection) - strlen(szProjection),
442 : ",UNIT[\"%s\",%.15g]", psGXF->pszUnitName,
443 : psGXF->dfUnitToMeter);
444 : }
445 :
446 : /* -------------------------------------------------------------------- */
447 : /* Build GEOGCS. There are still "issues" with the generation */
448 : /* of the GEOGCS/Datum and Spheroid names. Of these, only the */
449 : /* datum name is really significant. */
450 : /* -------------------------------------------------------------------- */
451 2 : if (CSLCount(psGXF->papszMapProjection) > 1)
452 : {
453 : char **papszTokens;
454 :
455 2 : if (strlen(psGXF->papszMapProjection[1]) > 80)
456 0 : return CPLStrdup("");
457 :
458 2 : papszTokens = CSLTokenizeStringComplex(psGXF->papszMapProjection[1],
459 : ",", TRUE, TRUE);
460 :
461 2 : if (CSLCount(papszTokens) > 2)
462 : {
463 2 : double dfMajor = CPLAtof(papszTokens[1]);
464 2 : double dfEccentricity = CPLAtof(papszTokens[2]);
465 : double dfInvFlattening, dfMinor;
466 : char *pszOGCDatum;
467 :
468 : /* translate eccentricity to inv flattening. */
469 2 : if (dfEccentricity == 0.0)
470 0 : dfInvFlattening = 0.0;
471 : else
472 : {
473 2 : dfMinor =
474 2 : dfMajor * pow(1.0 - dfEccentricity * dfEccentricity, 0.5);
475 2 : dfInvFlattening = OSRCalcInvFlattening(dfMajor, dfMinor);
476 : }
477 :
478 2 : pszOGCDatum = CPLStrdup(papszTokens[0]);
479 2 : WKTMassageDatum(&pszOGCDatum);
480 :
481 2 : CPLsnprintf(
482 : szGCS, sizeof(szGCS),
483 : "GEOGCS[\"%s\","
484 : "DATUM[\"%s\","
485 : "SPHEROID[\"%s\",%s,%.15g]],",
486 : papszTokens[0], pszOGCDatum,
487 : papszTokens[0], /* this is datum, but should be ellipse*/
488 2 : papszTokens[1], dfInvFlattening);
489 2 : CPLFree(pszOGCDatum);
490 : }
491 :
492 2 : if (CSLCount(papszTokens) > 3)
493 2 : CPLsnprintf(szGCS + strlen(szGCS), sizeof(szGCS) - strlen(szGCS),
494 2 : "PRIMEM[\"unnamed\",%s],", papszTokens[3]);
495 :
496 2 : CPLsnprintf(szGCS + strlen(szGCS), sizeof(szGCS) - strlen(szGCS), "%s",
497 : "UNIT[\"degree\",0.0174532925199433]]");
498 :
499 2 : CSLDestroy(papszTokens);
500 : }
501 :
502 2 : CPLAssert(strlen(szProjection) < sizeof(szProjection));
503 2 : CPLAssert(strlen(szGCS) < sizeof(szGCS));
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Put this all together into a full projection. */
507 : /* -------------------------------------------------------------------- */
508 2 : if (strlen(szProjection) > 0)
509 : {
510 2 : if (strlen(psGXF->papszMapProjection[0]) > 80)
511 0 : return CPLStrdup("");
512 :
513 2 : if (psGXF->papszMapProjection[0][0] == '"')
514 2 : snprintf(szWKT, sizeof(szWKT), "PROJCS[%s,%s,%s]",
515 2 : psGXF->papszMapProjection[0], szGCS, szProjection);
516 : else
517 0 : snprintf(szWKT, sizeof(szWKT), "PROJCS[\"%s\",%s,%s]",
518 0 : psGXF->papszMapProjection[0], szGCS, szProjection);
519 : }
520 : else
521 : {
522 0 : strcpy(szWKT, szGCS);
523 : }
524 :
525 2 : return (CPLStrdup(szWKT));
526 : }
|