GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-ab016ef450
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
convert.c
Go to the documentation of this file.
1 /*!
2  \file lib/proj/convert.c
3 
4  \brief GProj Library - Functions for manipulating co-ordinate
5  system representations
6 
7  (C) 2003-2018 by the GRASS Development Team
8 
9  This program is free software under the GNU General Public License
10  (>=v2). Read the file COPYING that comes with GRASS for details.
11 
12  \author Paul Kelly, Frank Warmerdam, Markus Metz
13  */
14 
15 #include <grass/config.h>
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <math.h>
21 #include <grass/gis.h>
22 #include <grass/gprojects.h>
23 #include <grass/glocale.h>
24 
25 #ifdef HAVE_OGR
26 #include <cpl_csv.h>
27 #include "local_proto.h"
28 
29 /* GRASS relative location of OGR co-ordinate system lookup tables */
30 #define CSVDIR "/etc/proj/ogr_csv"
31 
32 static void DatumNameMassage(char **);
33 #endif
34 
35 /* from proj-5.0.0/src/pj_units.c */
36 struct gpj_units {
37  char *id; /* units keyword */
38  char *to_meter; /* multiply by value to get meters */
39  char *name; /* comments */
40  double factor; /* to_meter factor in actual numbers */
41 };
42 
43 struct gpj_units gpj_units[] = {
44  {"km", "1000.", "Kilometer", 1000.0},
45  {"m", "1.", "Meter", 1.0},
46  {"dm", "1/10", "Decimeter", 0.1},
47  {"cm", "1/100", "Centimeter", 0.01},
48  {"mm", "1/1000", "Millimeter", 0.001},
49  {"kmi", "1852.0", "International Nautical Mile", 1852.0},
50  {"in", "0.0254", "International Inch", 0.0254},
51  {"ft", "0.3048", "International Foot", 0.3048},
52  {"yd", "0.9144", "International Yard", 0.9144},
53  {"mi", "1609.344", "International Statute Mile", 1609.344},
54  {"fath", "1.8288", "International Fathom", 1.8288},
55  {"ch", "20.1168", "International Chain", 20.1168},
56  {"link", "0.201168", "International Link", 0.201168},
57  {"us-in", "1./39.37", "U.S. Surveyor's Inch", 0.0254},
58  {"us-ft", "0.304800609601219", "U.S. Surveyor's Foot", 0.304800609601219},
59  {"us-yd", "0.914401828803658", "U.S. Surveyor's Yard", 0.914401828803658},
60  {"us-ch", "20.11684023368047", "U.S. Surveyor's Chain", 20.11684023368047},
61  {"us-mi", "1609.347218694437", "U.S. Surveyor's Statute Mile",
62  1609.347218694437},
63  {"ind-yd", "0.91439523", "Indian Yard", 0.91439523},
64  {"ind-ft", "0.30479841", "Indian Foot", 0.30479841},
65  {"ind-ch", "20.11669506", "Indian Chain", 20.11669506},
66  {NULL, NULL, NULL, 0.0}};
67 
68 static char *grass_to_wkt(const struct Key_Value *proj_info,
69  const struct Key_Value *proj_units,
70  const struct Key_Value *proj_epsg, int esri_style,
71  int prettify)
72 {
73 #ifdef HAVE_OGR
74  OGRSpatialReferenceH hSRS;
75  char *wkt, *local_wkt;
76 
77  hSRS = GPJ_grass_to_osr2(proj_info, proj_units, proj_epsg);
78 
79  if (hSRS == NULL)
80  return NULL;
81 
82  if (esri_style)
83  OSRMorphToESRI(hSRS);
84 
85  if (prettify)
86  OSRExportToPrettyWkt(hSRS, &wkt, 0);
87  else
88  OSRExportToWkt(hSRS, &wkt);
89 
90  local_wkt = G_store(wkt);
91  CPLFree(wkt);
92  OSRDestroySpatialReference(hSRS);
93 
94  return local_wkt;
95 #else
96  G_warning(_("GRASS is not compiled with OGR support"));
97  return NULL;
98 #endif
99 }
100 
101 /*!
102  * \brief Converts a GRASS co-ordinate system representation to WKT style.
103  *
104  * Takes a GRASS co-ordinate system as specified by two sets of
105  * key/value pairs derived from the PROJ_INFO and PROJ_UNITS files,
106  * and converts it to the 'Well Known Text' format.
107  *
108  * \param proj_info Set of GRASS PROJ_INFO key/value pairs
109  * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
110  * \param esri_style boolean Output ESRI-style WKT (Use OSRMorphToESRI()
111  * function provided by OGR library)
112  * \param prettify boolean Use linebreaks and indents to 'prettify' output
113  * WKT string (Use OSRExportToPrettyWkt() function in OGR)
114  *
115  * \return Pointer to a string containing the co-ordinate system in
116  * WKT format
117  * \return NULL on error
118  */
119 char *GPJ_grass_to_wkt(const struct Key_Value *proj_info,
120  const struct Key_Value *proj_units, int esri_style,
121  int prettify)
122 {
123  return grass_to_wkt(proj_info, proj_units, NULL, esri_style, prettify);
124 }
125 
126 /*!
127  * \brief Converts a GRASS co-ordinate system representation to WKT
128  * style. EPSG code is preferred if available.
129  *
130  * Takes a GRASS co-ordinate system as specified key/value pairs
131  * derived from the PROJ_EPSG file. TOWGS84 parameter is scanned
132  * from PROJ_INFO file and appended to co-ordinate system definition
133  * imported from EPSG code by GDAL library. PROJ_UNITS file is
134  * ignored. The function converts it to the 'Well Known Text' format.
135  *
136  * \todo Merge with GPJ_grass_to_wkt() in GRASS 8.
137  *
138  * \param proj_info Set of GRASS PROJ_INFO key/value pairs
139  * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
140  * \param proj_epsg Set of GRASS PROJ_EPSG key/value pairs
141  * \param esri_style boolean Output ESRI-style WKT (Use OSRMorphToESRI()
142  * function provided by OGR library)
143  * \param prettify boolean Use linebreaks and indents to 'prettify' output
144  * WKT string (Use OSRExportToPrettyWkt() function in OGR)
145  *
146  * \return Pointer to a string containing the co-ordinate system in
147  * WKT format
148  * \return NULL on error
149  */
150 char *GPJ_grass_to_wkt2(const struct Key_Value *proj_info,
151  const struct Key_Value *proj_units,
152  const struct Key_Value *proj_epsg, int esri_style,
153  int prettify)
154 {
155  return grass_to_wkt(proj_info, proj_units, proj_epsg, esri_style, prettify);
156 }
157 
158 #ifdef HAVE_OGR
159 /*!
160  * \brief Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object.
161  *
162  * \param proj_info Set of GRASS PROJ_INFO key/value pairs
163  * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
164  *
165  * \return OGRSpatialReferenceH object representing the co-ordinate system
166  * defined by proj_info and proj_units or NULL if it fails
167  */
168 OGRSpatialReferenceH GPJ_grass_to_osr(const struct Key_Value *proj_info,
169  const struct Key_Value *proj_units)
170 {
171  struct pj_info pjinfo;
172  char *proj4, *proj4mod, *wkt, *modwkt, *startmod, *lastpart;
173  OGRSpatialReferenceH hSRS, hSRS2;
174  OGRErr errcode;
175  struct gpj_datum dstruct;
176  struct gpj_ellps estruct;
177  size_t len;
178  const char *ellpskv, *unit, *unfact;
179  char *ellps, *ellpslong, *datum, *params, *towgs84, *datumlongname, *start,
180  *end;
181  const char *sysname, *osrunit;
182  double a, es, rf;
183  int haveparams = 0;
184 
185  if ((proj_info == NULL) || (proj_units == NULL))
186  return NULL;
187 
188  hSRS = OSRNewSpatialReference(NULL);
189 
190  /* create PROJ structure from GRASS key/value pairs */
191  if (pj_get_kv(&pjinfo, proj_info, proj_units) < 0) {
192  G_warning(_("Unable parse GRASS PROJ_INFO file"));
193  return NULL;
194  }
195 
196  /* fetch the PROJ definition */
197  /* TODO: get the PROJ definition as used by pj_get_kv() */
198  if ((proj4 = pjinfo.def) == NULL) {
199  G_warning(_("Unable get PROJ.4-style parameter string"));
200  return NULL;
201  }
202 #ifdef HAVE_PROJ_H
203  proj_destroy(pjinfo.pj);
204 #else
205  pj_free(pjinfo.pj);
206 #endif
207 
208  unit = G_find_key_value("unit", proj_units);
209  unfact = G_find_key_value("meters", proj_units);
210  if (unfact != NULL && (strcmp(pjinfo.proj, "ll") != 0))
211  G_asprintf(&proj4mod, "%s +to_meter=%s", proj4, unfact);
212  else
213  proj4mod = G_store(proj4);
214 
215  /* create GDAL OSR from proj string */
216  if ((errcode = OSRImportFromProj4(hSRS, proj4mod)) != OGRERR_NONE) {
217  G_warning(_("OGR can't parse PROJ.4-style parameter string: "
218  "%s (OGR Error code was %d)"),
219  proj4mod, errcode);
220  return NULL;
221  }
222  G_free(proj4mod);
223 
224  /* this messes up PROJCS versus GEOGCS!
225  sysname = G_find_key_value("name", proj_info);
226  if (sysname)
227  OSRSetProjCS(hSRS, sysname);
228  */
229 
230  if ((errcode = OSRExportToWkt(hSRS, &wkt)) != OGRERR_NONE) {
231  G_warning(_("OGR can't get WKT-style parameter string "
232  "(OGR Error code was %d)"),
233  errcode);
234  return NULL;
235  }
236 
237  ellpskv = G_find_key_value("ellps", proj_info);
238  GPJ__get_ellipsoid_params(proj_info, &a, &es, &rf);
239  haveparams = GPJ__get_datum_params(proj_info, &datum, &params);
240 
241  if (ellpskv != NULL)
242  ellps = G_store(ellpskv);
243  else
244  ellps = NULL;
245 
246  if ((datum == NULL) || (GPJ_get_datum_by_name(datum, &dstruct) < 0)) {
247  datumlongname = G_store("unknown");
248  if (ellps == NULL)
249  ellps = G_store("unnamed");
250  }
251  else {
252  datumlongname = G_store(dstruct.longname);
253  if (ellps == NULL)
254  ellps = G_store(dstruct.ellps);
255  GPJ_free_datum(&dstruct);
256  }
257  G_debug(3, "GPJ_grass_to_osr: datum: <%s>", datum);
258  G_free(datum);
259  if (GPJ_get_ellipsoid_by_name(ellps, &estruct) > 0) {
260  ellpslong = G_store(estruct.longname);
261  DatumNameMassage(&ellpslong);
262  GPJ_free_ellps(&estruct);
263  }
264  else
265  ellpslong = G_store(ellps);
266 
267  startmod = strstr(wkt, "GEOGCS");
268  lastpart = strstr(wkt, "PRIMEM");
269  len = strlen(wkt) - strlen(startmod);
270  wkt[len] = '\0';
271  if (haveparams == 2) {
272  /* Only put datum params into the WKT if they were specifically
273  * specified in PROJ_INFO */
274  char *paramkey, *paramvalue;
275 
276  paramkey = strtok(params, "=");
277  paramvalue = params + strlen(paramkey) + 1;
278  if (G_strcasecmp(paramkey, "towgs84") == 0)
279  G_asprintf(&towgs84, ",TOWGS84[%s]", paramvalue);
280  else
281  towgs84 = G_store("");
282  G_free(params);
283  }
284  else
285  towgs84 = G_store("");
286 
287  sysname = OSRGetAttrValue(hSRS, "PROJCS", 0);
288  if (sysname == NULL) {
289  /* Not a projected co-ordinate system */
290  start = G_store("");
291  end = G_store("");
292  }
293  else {
294  if ((strcmp(sysname, "unnamed") == 0) &&
295  (G_find_key_value("name", proj_info) != NULL))
296  G_asprintf(&start, "PROJCS[\"%s\",",
297  G_find_key_value("name", proj_info));
298  else
299  start = G_store(wkt);
300 
301  osrunit = OSRGetAttrValue(hSRS, "UNIT", 0);
302 
303  if ((unfact == NULL) || (G_strcasecmp(osrunit, "unknown") != 0))
304  end = G_store("");
305  else {
306  char *buff;
307  double unfactf = atof(unfact);
308 
309  G_asprintf(&buff, ",UNIT[\"%s\",", osrunit);
310 
311  startmod = strstr(lastpart, buff);
312  len = strlen(lastpart) - strlen(startmod);
313  lastpart[len] = '\0';
314  G_free(buff);
315 
316  if (unit == NULL)
317  unit = "unknown";
318  G_asprintf(&end, ",UNIT[\"%s\",%.16g]]", unit, unfactf);
319  }
320  }
321  OSRDestroySpatialReference(hSRS);
322  G_asprintf(
323  &modwkt,
324  "%sGEOGCS[\"%s\",DATUM[\"%s\",SPHEROID[\"%s\",%.16g,%.16g]%s],%s%s",
325  start, ellps, datumlongname, ellpslong, a, rf, towgs84, lastpart, end);
326  hSRS2 = OSRNewSpatialReference(modwkt);
327  G_free(modwkt);
328 
329  CPLFree(wkt);
330  G_free(start);
331  G_free(ellps);
332  G_free(datumlongname);
333  G_free(ellpslong);
334  G_free(towgs84);
335  G_free(end);
336 
337  return hSRS2;
338 }
339 
340 /*!
341  * \brief Converts a GRASS co-ordinate system to an
342  * OGRSpatialReferenceH object. EPSG code is preferred if available.
343  *
344  * The co-ordinate system definition is imported from EPSG (by GDAL)
345  * definition if available. TOWGS84 parameter is scanned from
346  * PROJ_INFO file and appended to co-ordinate system definition. If
347  * EPSG code is not available, PROJ_INFO file is used as
348  * GPJ_grass_to_osr() does.
349 
350  * \todo Merge with GPJ_grass_to_osr() in GRASS 8.
351  *
352  * \param proj_info Set of GRASS PROJ_INFO key/value pairs
353  * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
354  * \param proj_epsg Set of GRASS PROJ_EPSG key/value pairs
355  *
356  * \return OGRSpatialReferenceH object representing the co-ordinate system
357  * defined by proj_info and proj_units or NULL if it fails
358  */
359 OGRSpatialReferenceH GPJ_grass_to_osr2(const struct Key_Value *proj_info,
360  const struct Key_Value *proj_units,
361  const struct Key_Value *proj_epsg)
362 {
363  int epsgcode = 0;
364 
365  if (proj_epsg) {
366  const char *epsgstr = G_find_key_value("epsg", proj_epsg);
367 
368  if (epsgstr)
369  epsgcode = atoi(epsgstr);
370  }
371 
372  if (epsgcode) {
373  const char *towgs84;
374  OGRSpatialReferenceH hSRS;
375 
376  hSRS = OSRNewSpatialReference(NULL);
377 
378  OSRImportFromEPSG(hSRS, epsgcode);
379 
380  /* take +towgs84 from projinfo file if defined */
381  towgs84 = G_find_key_value("towgs84", proj_info);
382  if (towgs84) {
383  char **tokens;
384  int i;
385  double df[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
386 
387  tokens = G_tokenize(towgs84, ",");
388 
389  for (i = 0; i < G_number_of_tokens(tokens); i++)
390  df[i] = atof(tokens[i]);
391  G_free_tokens(tokens);
392 
393  OSRSetTOWGS84(hSRS, df[0], df[1], df[2], df[3], df[4], df[5],
394  df[6]);
395  }
396 
397  return hSRS;
398  }
399 
400  return GPJ_grass_to_osr(proj_info, proj_units);
401 }
402 
403 /*!
404  * \brief Converts an OGRSpatialReferenceH object to a GRASS co-ordinate system.
405  *
406  * \param cellhd Pointer to a GRASS Cell_head structure that will have its
407  * projection-related members populated with appropriate
408  * values \param projinfo Pointer to a pointer which will have a GRASS
409  * Key_Value structure allocated containing a set of GRASS PROJ_INFO values
410  * \param projunits Pointer to a pointer which will have a GRASS Key_Value
411  * structure allocated containing a set of GRASS PROJ_UNITS
412  * values \param hSRS OGRSpatialReferenceH object containing the
413  * co-ordinate system to be converted \param datumtrans Index number of datum
414  * parameter set to use, 0 to leave unspecified
415  *
416  * \return 2 if a projected or lat/long co-ordinate system has been
417  * defined
418  * \return 1 if an unreferenced XY co-ordinate system has
419  * been defined
420  */
421 int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo,
422  struct Key_Value **projunits, OGRSpatialReferenceH hSRS1,
423  int datumtrans)
424 {
425  struct Key_Value *temp_projinfo, *temp_projinfo_ext;
426  char *pszProj4 = NULL, *pszRemaining;
427  char *pszProj = NULL;
428  const char *pszProjCS = NULL;
429  char *datum = NULL;
430  char *proj4_unit = NULL;
431  struct gpj_datum dstruct;
432  const char *ograttr;
433  OGRSpatialReferenceH hSRS;
434  int use_proj_extension;
435 
436  *projinfo = NULL;
437  *projunits = NULL;
438 
439  hSRS = hSRS1;
440 
441  if (hSRS == NULL)
442  goto default_to_xy;
443 
444  /* Set finder function for locating OGR csv co-ordinate system tables */
445  /* SetCSVFilenameHook(GPJ_set_csv_loc); */
446 
447  /* Hopefully this doesn't do any harm if it wasn't in ESRI format
448  * to start with... */
449  OSRMorphFromESRI(hSRS);
450 
451  *projinfo = G_create_key_value();
452  use_proj_extension = 0;
453 
454  /* use proj4 definition from EXTENSION attribute if existing */
455  ograttr = OSRGetAttrValue(hSRS, "EXTENSION", 0);
456  if (ograttr && *ograttr && strcmp(ograttr, "PROJ4") == 0) {
457  ograttr = OSRGetAttrValue(hSRS, "EXTENSION", 1);
458  G_debug(3, "proj4 extension:");
459  G_debug(3, "%s", ograttr);
460 
461  if (ograttr && *ograttr) {
462  char *proj4ext;
463  OGRSpatialReferenceH hSRS2;
464 
465  hSRS2 = OSRNewSpatialReference(NULL);
466  proj4ext = G_store(ograttr);
467 
468  /* test */
469  if (OSRImportFromProj4(hSRS2, proj4ext) != OGRERR_NONE) {
470  G_warning(_("Updating spatial reference with embedded proj4 "
471  "definition failed. "
472  "Proj4 definition: <%s>"),
473  proj4ext);
474  OSRDestroySpatialReference(hSRS2);
475  }
476  else {
477  /* use new OGR spatial reference defined with embedded proj4
478  * string */
479  /* TODO: replace warning with important_message once confirmed
480  * working */
481  G_warning(_("Updating spatial reference with embedded proj4 "
482  "definition"));
483 
484  /* --------------------------------------------------------------------
485  */
486  /* Derive the user name for the coordinate system. */
487  /* --------------------------------------------------------------------
488  */
489  pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0);
490  if (!pszProjCS)
491  pszProjCS = OSRGetAttrValue(hSRS, "GEOGCS", 0);
492 
493  if (pszProjCS) {
494  G_set_key_value("name", pszProjCS, *projinfo);
495  }
496  else if (pszProj) {
497  char path[4095];
498  char name[80];
499 
500  /* use name of the projection as name for the coordinate
501  * system */
502 
503  snprintf(path, sizeof(path), "%s/etc/proj/projections",
504  G_gisbase());
505  if (G_lookup_key_value_from_file(path, pszProj, name,
506  sizeof(name)) > 0)
507  G_set_key_value("name", name, *projinfo);
508  else
509  G_set_key_value("name", pszProj, *projinfo);
510  }
511 
512  /* the original hSRS1 is left as is, ok? */
513  hSRS = hSRS2;
514  use_proj_extension = 1;
515  }
516  G_free(proj4ext);
517  }
518  }
519 
520  /* -------------------------------------------------------------------- */
521  /* Set cellhd for well known coordinate systems. */
522  /* -------------------------------------------------------------------- */
523  if (!OSRIsGeographic(hSRS) && !OSRIsProjected(hSRS))
524  goto default_to_xy;
525 
526  if (cellhd) {
527  int bNorth;
528 
529  if (OSRIsGeographic(hSRS)) {
530  cellhd->proj = PROJECTION_LL;
531  cellhd->zone = 0;
532  }
533  else if (OSRGetUTMZone(hSRS, &bNorth) != 0) {
534  cellhd->proj = PROJECTION_UTM;
535  cellhd->zone = OSRGetUTMZone(hSRS, &bNorth);
536  if (!bNorth)
537  cellhd->zone *= -1;
538  }
539  else {
540  cellhd->proj = PROJECTION_OTHER;
541  cellhd->zone = 0;
542  }
543  }
544 
545  /* -------------------------------------------------------------------- */
546  /* Get the coordinate system definition in PROJ.4 format. */
547  /* -------------------------------------------------------------------- */
548  if (OSRExportToProj4(hSRS, &pszProj4) != OGRERR_NONE)
549  goto default_to_xy;
550 
551  /* -------------------------------------------------------------------- */
552  /* Parse the PROJ.4 string into key/value pairs. Do a bit of */
553  /* extra work to "GRASSify" the result. */
554  /* -------------------------------------------------------------------- */
555  temp_projinfo = G_create_key_value();
556  temp_projinfo_ext = G_create_key_value();
557 
558  /* Create "local" copy of proj4 string so we can modify and free it
559  * using GRASS functions */
560  pszRemaining = G_store(pszProj4);
561  CPLFree(pszProj4);
562  pszProj4 = pszRemaining;
563  while ((pszRemaining = strstr(pszRemaining, "+")) != NULL) {
564  char *pszToken, *pszValue;
565 
566  pszRemaining++;
567 
568  /* Advance pszRemaining to end of this token[=value] pair */
569  pszToken = pszRemaining;
570  while (*pszRemaining != ' ' && *pszRemaining != '\0')
571  pszRemaining++;
572 
573  if (*pszRemaining == ' ') {
574  *pszRemaining = '\0';
575  pszRemaining++;
576  }
577 
578  /* parse token, and value */
579  if (strstr(pszToken, "=") != NULL) {
580  pszValue = strstr(pszToken, "=");
581  *pszValue = '\0';
582  pszValue++;
583  }
584  else
585  pszValue = "defined";
586 
587  /* projection name */
588  if (G_strcasecmp(pszToken, "proj") == 0) {
589  /* The ll projection is known as longlat in PROJ.4 */
590  if (G_strcasecmp(pszValue, "longlat") == 0)
591  pszValue = "ll";
592 
593  pszProj = pszValue;
594  }
595 
596  /* Ellipsoid and datum handled separately below */
597  if (G_strcasecmp(pszToken, "ellps") == 0 ||
598  G_strcasecmp(pszToken, "a") == 0 ||
599  G_strcasecmp(pszToken, "b") == 0 ||
600  G_strcasecmp(pszToken, "es") == 0 ||
601  G_strcasecmp(pszToken, "rf") == 0 ||
602  G_strcasecmp(pszToken, "datum") == 0) {
603  G_set_key_value(pszToken, pszValue, temp_projinfo_ext);
604  continue;
605  }
606 
607  /* We will handle units separately */
608  if (G_strcasecmp(pszToken, "to_meter") == 0)
609  continue;
610 
611  if (G_strcasecmp(pszToken, "units") == 0) {
612  proj4_unit = G_store(pszValue);
613  continue;
614  }
615 
616  G_set_key_value(pszToken, pszValue, temp_projinfo);
617  }
618  if (!pszProj)
619  G_warning(_("No projection name! Projection parameters likely to be "
620  "meaningless."));
621 
622  /* -------------------------------------------------------------------- */
623  /* Derive the user name for the coordinate system. */
624  /* -------------------------------------------------------------------- */
625  if (!G_find_key_value("name", *projinfo)) {
626  pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0);
627  if (!pszProjCS)
628  pszProjCS = OSRGetAttrValue(hSRS, "GEOGCS", 0);
629 
630  if (pszProjCS) {
631  G_set_key_value("name", pszProjCS, *projinfo);
632  }
633  else if (pszProj) {
634  char path[4095];
635  char name[80];
636 
637  /* use name of the projection as name for the coordinate system */
638 
639  snprintf(path, sizeof(path), "%s/etc/proj/projections",
640  G_gisbase());
641  if (G_lookup_key_value_from_file(path, pszProj, name,
642  sizeof(name)) > 0)
643  G_set_key_value("name", name, *projinfo);
644  else
645  G_set_key_value("name", pszProj, *projinfo);
646  }
647  }
648 
649  /* -------------------------------------------------------------------- */
650  /* Find the GRASS datum name and choose parameters either */
651  /* interactively or not. */
652  /* -------------------------------------------------------------------- */
653 
654  {
655  const char *pszDatumNameConst;
656  struct datum_list *list, *listhead;
657  char *dum1, *dum2, *pszDatumName;
658  int paramspresent = GPJ__get_datum_params(temp_projinfo, &dum1, &dum2);
659 
660  if (!use_proj_extension)
661  pszDatumNameConst = OSRGetAttrValue(hSRS, "DATUM", 0);
662  else
663  pszDatumNameConst = G_find_key_value("datum", temp_projinfo_ext);
664 
665  if (pszDatumNameConst) {
666  /* Need to make a new copy of the string so we don't mess
667  * around with the memory inside the OGRSpatialReferenceH? */
668 
669  pszDatumName = G_store(pszDatumNameConst);
670  DatumNameMassage(&pszDatumName);
671  G_debug(3, "GPJ_osr_to_grass: pszDatumNameConst: <%s>",
672  pszDatumName);
673 
674  list = listhead = read_datum_table();
675 
676  while (list != NULL) {
677  if (G_strcasecmp(pszDatumName, list->longname) == 0) {
678  datum = G_store(list->name);
679  break;
680  }
681  list = list->next;
682  }
683  free_datum_list(listhead);
684 
685  if (datum == NULL) {
686  if (paramspresent < 2)
687  /* Only give warning if no parameters present */
688  G_debug(1,
689  "Datum <%s> not recognised by GRASS and no "
690  "parameters found",
691  pszDatumName);
692  }
693  else {
694  G_set_key_value("datum", datum, *projinfo);
695 
696  if (paramspresent < 2) {
697  /* If no datum parameters were imported from the OSR
698  * object then we should use the set specified by datumtrans
699  */
700  char *params, *chosenparams = NULL;
701  int paramsets;
702 
703  paramsets =
704  GPJ_get_default_datum_params_by_name(datum, &params);
705 
706  if (paramsets < 0)
707  G_debug(1,
708  "Datum <%s> apparently recognised by GRASS but "
709  "no parameters found. "
710  "You may want to look into this.",
711  datum);
712  else if (datumtrans > paramsets) {
713 
714  G_debug(
715  1,
716  "Invalid transformation number %d; valid range is "
717  "1 to %d. "
718  "Leaving datum transform parameters unspecified.",
719  datumtrans, paramsets);
720  datumtrans = 0;
721  }
722 
723  if (paramsets > 0) {
724  struct gpj_datum_transform_list *tlist, *old;
725 
726  tlist = GPJ_get_datum_transform_by_name(datum);
727 
728  if (tlist != NULL) {
729  do {
730  if (tlist->count == datumtrans)
731  chosenparams = G_store(tlist->params);
732  old = tlist;
733  tlist = tlist->next;
735  } while (tlist != NULL);
736  }
737  }
738 
739  if (chosenparams != NULL) {
740  char *paramkey, *paramvalue;
741 
742  paramkey = strtok(chosenparams, "=");
743  paramvalue = chosenparams + strlen(paramkey) + 1;
744  G_set_key_value(paramkey, paramvalue, *projinfo);
745  G_free(chosenparams);
746  }
747 
748  if (paramsets > 0)
749  G_free(params);
750  }
751  }
752  G_free(pszDatumName);
753  }
754  }
755 
756  /* -------------------------------------------------------------------- */
757  /* Determine an appropriate GRASS ellipsoid name if possible, or */
758  /* else just put a and es values into PROJ_INFO */
759  /* -------------------------------------------------------------------- */
760 
761  if ((datum != NULL) && (GPJ_get_datum_by_name(datum, &dstruct) > 0)) {
762  /* Use ellps name associated with datum */
763  G_set_key_value("ellps", dstruct.ellps, *projinfo);
764  GPJ_free_datum(&dstruct);
765  G_free(datum);
766  }
767  else if (!use_proj_extension) {
768  /* If we can't determine the ellipsoid from the datum, derive it
769  * directly from "SPHEROID" parameters in WKT */
770  const char *pszSemiMajor = OSRGetAttrValue(hSRS, "SPHEROID", 1);
771  const char *pszInvFlat = OSRGetAttrValue(hSRS, "SPHEROID", 2);
772 
773  if (pszSemiMajor != NULL && pszInvFlat != NULL) {
774  char *ellps = NULL;
775  struct ellps_list *list, *listhead;
776  double a = atof(pszSemiMajor), invflat = atof(pszInvFlat), flat;
777  double es;
778 
779  /* Allow for incorrect WKT describing a sphere where InvFlat
780  * is given as 0 rather than inf */
781  if (invflat > 0)
782  flat = 1 / invflat;
783  else
784  flat = 0;
785 
786  es = flat * (2.0 - flat);
787 
788  list = listhead = read_ellipsoid_table(0);
789 
790  while (list != NULL) {
791  /* Try and match a and es against GRASS defined ellipsoids;
792  * accept first one that matches. These numbers were found
793  * by trial and error and could be fine-tuned, or possibly
794  * a direct comparison of IEEE floating point values used. */
795  if ((a == list->a || fabs(a - list->a) < 0.1 ||
796  fabs(1 - a / list->a) < 0.0000001) &&
797  ((es == 0 && list->es == 0) ||
798  /* Special case for sphere */
799  (invflat == list->rf ||
800  fabs(invflat - list->rf) < 0.0000001))) {
801  ellps = G_store(list->name);
802  break;
803  }
804  list = list->next;
805  }
806  if (listhead != NULL)
807  free_ellps_list(listhead);
808 
809  if (ellps == NULL) {
810  /* If we weren't able to find a matching ellps name, set
811  * a and es values directly from WKT-derived data */
812  char es_str[100];
813 
814  G_set_key_value("a", (char *)pszSemiMajor, *projinfo);
815 
816  snprintf(es_str, sizeof(es_str), "%.16g", es);
817  G_set_key_value("es", es_str, *projinfo);
818  }
819  else {
820  /* else specify the GRASS ellps name for readability */
821  G_set_key_value("ellps", ellps, *projinfo);
822  G_free(ellps);
823  }
824  }
825  }
826  else if (use_proj_extension) {
827  double a, es, rf;
828 
829  if (GPJ__get_ellipsoid_params(temp_projinfo_ext, &a, &es, &rf)) {
830  char parmstr[100];
831 
832  snprintf(parmstr, sizeof(parmstr), "%.16g", a);
833  G_set_key_value("a", parmstr, *projinfo);
834  snprintf(parmstr, sizeof(parmstr), "%.16g", es);
835  G_set_key_value("es", parmstr, *projinfo);
836  }
837  }
838 
839  /* -------------------------------------------------------------------- */
840  /* Finally append the detailed projection parameters to the end */
841  /* -------------------------------------------------------------------- */
842 
843  {
844  int i;
845 
846  for (i = 0; i < temp_projinfo->nitems; i++)
847  G_set_key_value(temp_projinfo->key[i], temp_projinfo->value[i],
848  *projinfo);
849 
850  G_free_key_value(temp_projinfo);
851  }
852  G_free_key_value(temp_projinfo_ext);
853 
854  G_free(pszProj4);
855 
856  /* -------------------------------------------------------------------- */
857  /* Set the linear units. */
858  /* -------------------------------------------------------------------- */
859  *projunits = G_create_key_value();
860 
861  if (OSRIsGeographic(hSRS)) {
862  /* We assume degrees ... someday we will be wrong! */
863  G_set_key_value("unit", "degree", *projunits);
864  G_set_key_value("units", "degrees", *projunits);
865  G_set_key_value("meters", "1.0", *projunits);
866  }
867  else {
868  char szFormatBuf[256];
869  char *pszUnitsName = NULL;
870  double dfToMeters;
871  char *pszUnitsPlural, *pszStringEnd;
872 
873  dfToMeters = OSRGetLinearUnits(hSRS, &pszUnitsName);
874 
875  /* the unit name can be arbitrary: the following can be the same
876  * us-ft (proj.4 keyword)
877  * U.S. Surveyor's Foot (proj.4 name)
878  * US survey foot (WKT)
879  * Foot_US (WKT)
880  */
881 
882  /* Workaround for the most obvious case when unit name is unknown */
883  if ((G_strcasecmp(pszUnitsName, "unknown") == 0) && (dfToMeters == 1.))
884  G_asprintf(&pszUnitsName, "meter");
885 
886  if ((G_strcasecmp(pszUnitsName, "metre") == 0))
887  G_asprintf(&pszUnitsName, "meter");
888  if ((G_strcasecmp(pszUnitsName, "kilometre") == 0))
889  G_asprintf(&pszUnitsName, "kilometer");
890 
891  if (dfToMeters != 1. && proj4_unit) {
892  int i;
893 
894  i = 0;
895  while (gpj_units[i].id != NULL) {
896  if (strcmp(proj4_unit, gpj_units[i].id) == 0) {
897  G_asprintf(&pszUnitsName, "%s", gpj_units[i].name);
898  break;
899  }
900  i++;
901  }
902  }
903 
904  G_set_key_value("unit", pszUnitsName, *projunits);
905 
906  /* Attempt at plural formation (WKT format doesn't store plural
907  * form of unit name) */
908  pszUnitsPlural = G_malloc(strlen(pszUnitsName) + 3);
909  strcpy(pszUnitsPlural, pszUnitsName);
910  pszStringEnd = pszUnitsPlural + strlen(pszUnitsPlural) - 4;
911  if (G_strcasecmp(pszStringEnd, "foot") == 0) {
912  /* Special case for foot - change two o's to e's */
913  pszStringEnd[1] = 'e';
914  pszStringEnd[2] = 'e';
915  }
916  else if (G_strcasecmp(pszStringEnd, "inch") == 0) {
917  /* Special case for inch - add es */
918  pszStringEnd[4] = 'e';
919  pszStringEnd[5] = 's';
920  pszStringEnd[6] = '\0';
921  }
922  else {
923  /* For anything else add an s at the end */
924  pszStringEnd[4] = 's';
925  pszStringEnd[5] = '\0';
926  }
927 
928  G_set_key_value("units", pszUnitsPlural, *projunits);
929  G_free(pszUnitsPlural);
930 
931  snprintf(szFormatBuf, sizeof(szFormatBuf), "%.16g", dfToMeters);
932  G_set_key_value("meters", szFormatBuf, *projunits);
933  }
934 
935  if (hSRS != hSRS1)
936  OSRDestroySpatialReference(hSRS);
937 
938  return 2;
939 
940  /* -------------------------------------------------------------------- */
941  /* Fallback to returning an ungeoreferenced definition. */
942  /* -------------------------------------------------------------------- */
943 default_to_xy:
944  if (cellhd != NULL) {
945  cellhd->proj = PROJECTION_XY;
946  cellhd->zone = 0;
947  }
948  if (*projinfo)
949  G_free_key_value(*projinfo);
950 
951  *projinfo = NULL;
952  *projunits = NULL;
953 
954  if (hSRS != NULL && hSRS != hSRS1)
955  OSRDestroySpatialReference(hSRS);
956 
957  return 1;
958 }
959 #endif
960 
961 /*!
962  * \brief Converts a WKT projection description to a GRASS co-ordinate system.
963  *
964  * \param cellhd Pointer to a GRASS Cell_head structure that will have its
965  * projection-related members populated with appropriate
966  * values \param projinfo Pointer to a pointer which will have a GRASS
967  * Key_Value structure allocated containing a set of GRASS PROJ_INFO values
968  * \param projunits Pointer to a pointer which will have a GRASS Key_Value
969  * structure allocated containing a set of GRASS PROJ_UNITS
970  * values \param wkt Well-known Text (WKT) description of the
971  * co-ordinate system to be converted \param datumtrans Index number of datum
972  * parameter set to use, 0 to leave unspecified
973  *
974  * \return 2 if a projected or lat/long co-ordinate system has been
975  * defined
976  * \return 1 if an unreferenced XY co-ordinate system has
977  * been defined
978  * \return -1 on error
979  */
980 int GPJ_wkt_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo,
981  struct Key_Value **projunits, const char *wkt,
982  int datumtrans)
983 {
984 #ifdef HAVE_OGR
985  int retval;
986 
987  if (wkt == NULL)
988  retval =
989  GPJ_osr_to_grass(cellhd, projinfo, projunits, NULL, datumtrans);
990  else {
991  OGRSpatialReferenceH hSRS;
992 
993  /* Set finder function for locating OGR csv co-ordinate system tables */
994  /* SetCSVFilenameHook(GPJ_set_csv_loc); */
995 
996  hSRS = OSRNewSpatialReference(wkt);
997  retval =
998  GPJ_osr_to_grass(cellhd, projinfo, projunits, hSRS, datumtrans);
999  OSRDestroySpatialReference(hSRS);
1000  }
1001 
1002  return retval;
1003 #else
1004  return -1;
1005 #endif
1006 }
1007 
1008 #ifdef HAVE_OGR
1009 /* GPJ_set_csv_loc()
1010  * 'finder function' for use with OGR SetCSVFilenameHook() function */
1011 
1012 const char *GPJ_set_csv_loc(const char *name)
1013 {
1014  const char *gisbase = G_gisbase();
1015  static char *buf = NULL;
1016 
1017  if (buf != NULL)
1018  G_free(buf);
1019 
1020  G_asprintf(&buf, "%s%s/%s", gisbase, CSVDIR, name);
1021 
1022  return buf;
1023 }
1024 
1025 /* The list below is only for files that use a non-standard name for a
1026  * datum that is already supported in GRASS. The number of entries must be even;
1027  * they are all in pairs. The first one in the pair is the non-standard name;
1028  * the second is the GRASS/GDAL name. If a name appears more than once (as for
1029  * European_Terrestrial_Reference_System_1989) then it means there was more
1030  * than one non-standard name for it that needs to be accounted for.
1031  *
1032  * N.B. The order of these pairs is different from that in
1033  * ogr/ogrfromepsg.cpp in the GDAL source tree! GRASS uses the EPSG
1034  * names in its WKT representation except WGS_1984 and WGS_1972 as
1035  * these shortened versions seem to be standard.
1036  * Below order:
1037  * the equivalent name comes first in the pair, and
1038  * the EPSG name (as used in the GRASS datum.table file) comes second.
1039  *
1040  * The datum parameters are stored in
1041  * ../gis/datum.table # 3 parameters
1042  * ../gis/datumtransform.table # 7 parameters (requires entry in datum.table)
1043  *
1044  * Hint: use GDAL's "testepsg" to identify the canonical name, e.g.
1045  * testepsg epsg:4674
1046  */
1047 
1048 static const char *papszDatumEquiv[] = {
1049  "Militar_Geographische_Institute",
1050  "Militar_Geographische_Institut",
1051  "World_Geodetic_System_1984",
1052  "WGS_1984",
1053  "World_Geodetic_System_1972",
1054  "WGS_1972",
1055  "European_Terrestrial_Reference_System_89",
1056  "European_Terrestrial_Reference_System_1989",
1057  "European_Reference_System_1989",
1058  "European_Terrestrial_Reference_System_1989",
1059  "ETRS_1989",
1060  "European_Terrestrial_Reference_System_1989",
1061  "ETRS89",
1062  "European_Terrestrial_Reference_System_1989",
1063  "ETRF_1989",
1064  "European_Terrestrial_Reference_System_1989",
1065  "NZGD_2000",
1066  "New_Zealand_Geodetic_Datum_2000",
1067  "Monte_Mario_Rome",
1068  "Monte_Mario",
1069  "MONTROME",
1070  "Monte_Mario",
1071  "Campo_Inchauspe_1969",
1072  "Campo_Inchauspe",
1073  "S_JTSK",
1074  "System_Jednotne_Trigonometricke_Site_Katastralni",
1075  "S_JTSK_Ferro",
1076  "Militar_Geographische_Institut",
1077  "Potsdam_Datum_83",
1078  "Deutsches_Hauptdreiecksnetz",
1079  "Rauenberg_Datum_83",
1080  "Deutsches_Hauptdreiecksnetz",
1081  "South_American_1969",
1082  "South_American_Datum_1969",
1083  "International_Terrestrial_Reference_Frame_1992",
1084  "ITRF92",
1085  "ITRF_1992",
1086  "ITRF92",
1087  NULL};
1088 
1089 /************************************************************************/
1090 /* OGREPSGDatumNameMassage() */
1091 /* */
1092 /* Massage an EPSG datum name into WMT format. Also transform */
1093 /* specific exception cases into WKT versions. */
1094 
1095 /************************************************************************/
1096 
1097 static void DatumNameMassage(char **ppszDatum)
1098 {
1099  int i, j;
1100  char *pszDatum = *ppszDatum;
1101 
1102  G_debug(3, "DatumNameMassage: Raw string found <%s>", (char *)pszDatum);
1103  /* -------------------------------------------------------------------- */
1104  /* Translate non-alphanumeric values to underscores. */
1105  /* -------------------------------------------------------------------- */
1106  for (i = 0; pszDatum[i] != '\0'; i++) {
1107  if (!(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z') &&
1108  !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z') &&
1109  !(pszDatum[i] >= '0' && pszDatum[i] <= '9')) {
1110  pszDatum[i] = '_';
1111  }
1112  }
1113 
1114  /* -------------------------------------------------------------------- */
1115  /* Remove repeated and trailing underscores. */
1116  /* -------------------------------------------------------------------- */
1117  for (i = 1, j = 0; pszDatum[i] != '\0'; i++) {
1118  if (pszDatum[j] == '_' && pszDatum[i] == '_')
1119  continue;
1120 
1121  pszDatum[++j] = pszDatum[i];
1122  }
1123  if (pszDatum[j] == '_')
1124  pszDatum[j] = '\0';
1125  else
1126  pszDatum[j + 1] = '\0';
1127 
1128  /* -------------------------------------------------------------------- */
1129  /* Search for datum equivalences. Specific massaged names get */
1130  /* mapped to OpenGIS specified names. */
1131  /* -------------------------------------------------------------------- */
1132  G_debug(3, "DatumNameMassage: Search for datum equivalences of <%s>",
1133  (char *)pszDatum);
1134  for (i = 0; papszDatumEquiv[i] != NULL; i += 2) {
1135  if (EQUAL(*ppszDatum, papszDatumEquiv[i])) {
1136  G_free(*ppszDatum);
1137  *ppszDatum = G_store(papszDatumEquiv[i + 1]);
1138  break;
1139  }
1140  }
1141 }
1142 
1143 #endif /* HAVE_OGR */
#define NULL
Definition: ccmath.h:32
#define CSVDIR
Definition: convert.c:30
struct gpj_units gpj_units[]
Definition: convert.c:43
OGRSpatialReferenceH GPJ_grass_to_osr2(const struct Key_Value *proj_info, const struct Key_Value *proj_units, const struct Key_Value *proj_epsg)
Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object. EPSG code is preferred if avai...
Definition: convert.c:359
const char * GPJ_set_csv_loc(const char *name)
Definition: convert.c:1012
int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, struct Key_Value **projunits, OGRSpatialReferenceH hSRS1, int datumtrans)
Converts an OGRSpatialReferenceH object to a GRASS co-ordinate system.
Definition: convert.c:421
int GPJ_wkt_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, struct Key_Value **projunits, const char *wkt, int datumtrans)
Converts a WKT projection description to a GRASS co-ordinate system.
Definition: convert.c:980
char * GPJ_grass_to_wkt2(const struct Key_Value *proj_info, const struct Key_Value *proj_units, const struct Key_Value *proj_epsg, int esri_style, int prettify)
Converts a GRASS co-ordinate system representation to WKT style. EPSG code is preferred if available.
Definition: convert.c:150
OGRSpatialReferenceH GPJ_grass_to_osr(const struct Key_Value *proj_info, const struct Key_Value *proj_units)
Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object.
Definition: convert.c:168
char * GPJ_grass_to_wkt(const struct Key_Value *proj_info, const struct Key_Value *proj_units, int esri_style, int prettify)
Converts a GRASS co-ordinate system representation to WKT style.
Definition: convert.c:119
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void G_warning(const char *,...) __attribute__((format(printf
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
Definition: key_value1.c:85
#define G_malloc(n)
Definition: defs/gis.h:94
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
Definition: key_value1.c:104
void G_set_key_value(const char *, const char *, struct Key_Value *)
Set value for given key.
Definition: key_value1.c:39
int G_lookup_key_value_from_file(const char *, const char *, char[], int)
Look up for key in file.
Definition: key_value4.c:48
void G_free_tokens(char **)
Free memory allocated to tokens.
Definition: gis/token.c:198
int G_asprintf(char **, const char *,...) __attribute__((format(printf
int G_number_of_tokens(char **)
Return number of tokens.
Definition: gis/token.c:179
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:39
struct Key_Value * G_create_key_value(void)
Allocate and initialize Key_Value structure.
Definition: key_value1.c:23
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
char ** G_tokenize(const char *, const char *)
Tokenize string.
Definition: gis/token.c:47
struct gpj_datum_transform_list * GPJ_get_datum_transform_by_name(const char *)
Internal function to find all possible sets of transformation parameters for a particular datum.
Definition: proj/datum.c:237
void GPJ_free_datum(struct gpj_datum *)
Free the memory used for the strings in a gpj_datum struct.
Definition: proj/datum.c:396
int GPJ_get_ellipsoid_by_name(const char *, struct gpj_ellps *)
Looks up ellipsoid in ellipsoid table and returns the a, e2 parameters for the ellipsoid.
Definition: ellipse.c:160
int GPJ_get_datum_by_name(const char *, struct gpj_datum *)
Look up a string in datum.table file to see if it is a valid datum name and if so place its informati...
Definition: proj/datum.c:38
void GPJ_free_ellps(struct gpj_ellps *)
Free ellipsoid data structure.
Definition: ellipse.c:303
int GPJ_get_default_datum_params_by_name(const char *, char **)
"Last resort" function to retrieve a "default" set of datum parameters for a datum (N....
Definition: proj/datum.c:86
int GPJ__get_datum_params(const struct Key_Value *, char **, char **)
Extract the datum transformation-related parameters from a set of general PROJ_INFO parameters.
Definition: proj/datum.c:173
int pj_get_kv(struct pj_info *, const struct Key_Value *, const struct Key_Value *)
Create a pj_info struct Co-ordinate System definition from a set of PROJ_INFO / PROJ_UNITS-style key-...
Definition: get_proj.c:60
int GPJ__get_ellipsoid_params(const struct Key_Value *, double *, double *, double *)
Get the ellipsoid parameters from proj keys structure.
Definition: ellipse.c:74
void GPJ_free_datum_transform(struct gpj_datum_transform_list *)
Free the memory used by a gpj_datum_transform_list struct.
Definition: proj/datum.c:323
struct ellps_list * read_ellipsoid_table(int fatal)
Definition: ellipse.c:224
void free_ellps_list(struct ellps_list *elist)
Definition: ellipse.c:310
#define PROJECTION_OTHER
Projection code - other projection (other then noted above)
Definition: gis.h:131
#define PROJECTION_XY
Projection code - XY coordinate system (unreferenced data)
Definition: gis.h:123
#define PROJECTION_UTM
Projection code - UTM.
Definition: gis.h:125
#define PROJECTION_LL
Projection code - Latitude-Longitude.
Definition: gis.h:129
#define _(str)
Definition: glocale.h:10
const char * name
Definition: named_colr.c:6
#define strcpy
Definition: parson.c:62
void free_datum_list(struct datum_list *dstruct)
Free the memory used by a datum_list linked list structure.
Definition: proj/datum.c:410
struct datum_list * read_datum_table(void)
Read the current GRASS datum.table from disk and store in memory.
Definition: proj/datum.c:342
struct list * list
Definition: read_list.c:24
@ EQUAL
Definition: sqlp.tab.h:65
2D/3D raster map header (used also for region)
Definition: gis.h:440
int zone
Projection zone (UTM)
Definition: gis.h:474
int proj
Projection code.
Definition: gis.h:472
Definition: gis.h:528
char ** value
Definition: gis.h:532
int nitems
Definition: gis.h:529
char ** key
Definition: gis.h:531
struct gpj_datum_transform_list * next
Definition: gprojects.h:102
char * longname
Definition: gprojects.h:86
char * ellps
Definition: gprojects.h:86
double es
Definition: gprojects.h:109
double a
Definition: gprojects.h:109
double rf
Definition: gprojects.h:109
char * longname
Definition: gprojects.h:108
Definition: manage.h:4
Definition: path.h:15
char proj[100]
Definition: gprojects.h:79
char * def
Definition: gprojects.h:80
PJ * pj
Definition: gprojects.h:73
char * wkt
Definition: gprojects.h:82