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