GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-bb27c0570b
proj/datum.c
Go to the documentation of this file.
1 /**
2  \file lib/proj/datum.c
3 
4  \brief GProj library - Functions for reading datum parameters from the
5 location database
6 
7  \author Andreas Lange <andreas.lange rhein-main.de>, Paul Kelly <paul-grass
8 stjohnspoint.co.uk>
9 
10  (C) 2003-2008 by the GRASS Development Team
11 
12  This program is free software under the GNU General Public
13  License (>=v2). Read the file COPYING that comes with GRASS
14  for details.
15 **/
16 
17 #include <unistd.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <stdlib.h>
21 
22 #include <grass/gis.h>
23 #include <grass/glocale.h>
24 #include <grass/gprojects.h>
25 #include "local_proto.h"
26 
27 /**
28  * \brief Look up a string in datum.table file to see if it is a valid datum
29  * name and if so place its information into a gpj_datum struct
30  *
31  * \param name String containing datum name to look up
32  * \param dstruct gpj_datum struct into which datum parameters will be placed
33  * if found
34  *
35  * \return 1 if datum found, -1 if not
36  **/
37 
38 int GPJ_get_datum_by_name(const char *name, struct gpj_datum *dstruct)
39 {
40  struct datum_list *list, *listhead;
41 
42  list = listhead = read_datum_table();
43 
44  while (list != NULL) {
45  if (G_strcasecmp(name, list->name) == 0) {
46  dstruct->name = G_store(list->name);
47  dstruct->longname = G_store(list->longname);
48  dstruct->ellps = G_store(list->ellps);
49  dstruct->dx = list->dx;
50  dstruct->dy = list->dy;
51  dstruct->dz = list->dz;
52  free_datum_list(listhead);
53  return 1;
54  }
55  list = list->next;
56  }
57  free_datum_list(listhead);
58  return -1;
59 }
60 
61 /**
62  * \brief "Last resort" function to retrieve a "default" set of datum
63  * parameters for a datum (N.B. there really is no such thing as a
64  * catch-all default!)
65  *
66  * Kind of a "last resort" function as there really is no such thing
67  * as a default set of datum transformation parameters. Only should
68  * really be used where user interaction to choose a set of parameters
69  * is not desirable. Use of this function is not likely to result in
70  * selection of the optimum set of datum transformation parameters
71  * for the location
72  *
73  * \param name String containing GRASS datum name for which default
74  * parameters are to be retrieved
75  *
76  * \param params Pointer to a pointer which will have memory
77  * allocated and into which a string containing
78  * the datum parameters (if present) will
79  * be placed
80  *
81  * \return The number of possible parameter sets GRASS knows
82  * about for this datum
83  *
84  **/
85 
86 int GPJ_get_default_datum_params_by_name(const char *name, char **params)
87 {
88  struct gpj_datum_transform_list *list, *old;
89  int count = 0;
90 
92 
93  if (list == NULL) {
94  *params = NULL;
95  return -1;
96  }
97 
98  /* Take the first parameter set in the list as the default
99  * (will normally be a 3-parameter transformation) */
100  *params = G_store(list->params);
101 
102  while (list != NULL) {
103  count++;
104  old = list;
105  list = list->next;
107  }
108 
109  return count;
110 }
111 
112 /**
113  *
114  * \brief Extract the datum transformation-related parameters for
115  * the current location.
116  *
117  * This function can be used to test if a location's co-ordinate
118  * system set-up supports datum transformation.
119  *
120  * \param name Pointer to a pointer which will have memory
121  * allocated and into which a string containing the
122  * datum name (if present) will be placed. Otherwise
123  * set to NULL.
124  *
125  * \param params Pointer to a pointer which will have memory
126  * allocated and into which a string containing
127  * the datum parameters (if present) will
128  * be placed. Otherwise set to NULL.
129  *
130  * \return -1 error or no datum information found,
131  * 1 only datum name found, 2 params found
132  *
133  **/
134 
135 int GPJ_get_datum_params(char **name, char **params)
136 {
137  int ret;
138  struct Key_Value *proj_keys = G_get_projinfo();
139 
140  ret = GPJ__get_datum_params(proj_keys, name, params);
141  G_free_key_value(proj_keys);
142 
143  return ret;
144 }
145 
146 /**
147  *
148  * \brief Extract the datum transformation-related parameters from a
149  * set of general PROJ_INFO parameters.
150  *
151  * This function can be used to test if a location's co-ordinate
152  * system set-up supports datum transformation.
153  *
154  * \param projinfo Set of key_value pairs containing
155  * projection information in PROJ_INFO file
156  * format
157  *
158  * \param datumname Pointer to a pointer which will have memory
159  * allocated and into which a string containing the
160  * datum name (if present) will be placed. Otherwise
161  * set to NULL.
162  *
163  * \param params Pointer to a pointer which will have memory
164  * allocated and into which a string containing
165  * the datum parameters (if present) will
166  * be placed. Otherwise set to NULL.
167  *
168  * \return -1 error or no datum information found,
169  * 1 only datum name found, 2 params found
170  *
171  **/
172 
173 int GPJ__get_datum_params(const struct Key_Value *projinfo, char **datumname,
174  char **params)
175 {
176  int returnval = -1;
177 
178  if (NULL != G_find_key_value("datum", projinfo)) {
179  *datumname = G_store(G_find_key_value("datum", projinfo));
180  G_debug(3, "GPJ__get_datum_params: datumname: <%s>",
181  G_find_key_value("datum", projinfo));
182  returnval = 1;
183  }
184  else
185  *datumname = NULL;
186 
187  if (G_find_key_value("datumparams", projinfo) != NULL) {
188  *params = G_store(G_find_key_value("datumparams", projinfo));
189  G_debug(3, "GPJ__get_datum_params: datumparams: <%s>",
190  G_find_key_value("datumparams", projinfo));
191  returnval = 2;
192  }
193  else if (G_find_key_value("nadgrids", projinfo) != NULL) {
194  /* 1. beware of '@', do not create something like
195  * /usr/share/proj/@null, correct is @null or
196  * @/usr/share/proj/null
197  * 2. do not add path to the grid, there might already be a
198  * path, and it is safer to use pj_set_finder with PROJ.4 in
199  * datum.c */
200 
201  G_asprintf(params, "nadgrids=%s",
202  G_find_key_value("nadgrids", projinfo));
203 
204  returnval = 2;
205  }
206  else if (G_find_key_value("towgs84", projinfo) != NULL) {
207  G_asprintf(params, "towgs84=%s", G_find_key_value("towgs84", projinfo));
208  returnval = 2;
209  }
210  else if (G_find_key_value("dx", projinfo) != NULL &&
211  G_find_key_value("dy", projinfo) != NULL &&
212  G_find_key_value("dz", projinfo) != NULL) {
213  G_asprintf(params, "towgs84=%s,%s,%s", G_find_key_value("dx", projinfo),
214  G_find_key_value("dy", projinfo),
215  G_find_key_value("dz", projinfo));
216  returnval = 2;
217  }
218  else
219  *params = NULL;
220 
221  return returnval;
222 }
223 
224 /**
225  * \brief Internal function to find all possible sets of
226  * transformation parameters for a particular datum
227  *
228  * \param inputname String containing the datum name we
229  * are going to look up parameters for
230  *
231  * \return Pointer to struct gpj_datum_transform_list (a linked
232  * list containing transformation parameters),
233  * or NULL if no suitable parameters were found.
234  **/
235 
237 GPJ_get_datum_transform_by_name(const char *inputname)
238 {
239  FILE *fd;
240  char file[GPATH_MAX];
241  char buf[1024];
242  int line;
243  struct gpj_datum_transform_list *current = NULL, *outputlist = NULL;
244  struct gpj_datum dstruct;
245  int count = 0;
246 
247  GPJ_get_datum_by_name(inputname, &dstruct);
248  if (dstruct.dx < 99999 && dstruct.dy < 99999 && dstruct.dz < 99999) {
249  /* Include the old-style dx dy dz parameters from datum.table at the
250  * start of the list, unless these have been set to all 99999 to
251  * indicate only entries in datumtransform.table should be used */
252  if (current == NULL)
253  current = outputlist =
254  G_malloc(sizeof(struct gpj_datum_transform_list));
255  else
256  current = current->next =
257  G_malloc(sizeof(struct gpj_datum_transform_list));
258  G_asprintf(&(current->params), "towgs84=%.3f,%.3f,%.3f", dstruct.dx,
259  dstruct.dy, dstruct.dz);
260  G_asprintf(&(current->where_used), "whole %s region", inputname);
261  G_asprintf(&(current->comment),
262  "Default 3-Parameter Transformation (May not be optimum for "
263  "older datums; use this only if no more appropriate options "
264  "are available.)");
265  count++;
266  current->count = count;
267  current->next = NULL;
268  }
269  GPJ_free_datum(&dstruct);
270 
271  /* Now check for additional parameters in datumtransform.table */
272 
273  sprintf(file, "%s%s", G_gisbase(), DATUMTRANSFORMTABLE);
274 
275  fd = fopen(file, "r");
276  if (!fd) {
277  G_warning(_("Unable to open datum table file <%s>"), file);
278  return outputlist;
279  }
280 
281  for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
282  char name[100], params[1024], where_used[1024], comment[1024];
283 
284  G_strip(buf);
285  if (*buf == '\0' || *buf == '#')
286  continue;
287 
288  if (sscanf(buf, "%99s \"%1023[^\"]\" \"%1023[^\"]\" \"%1023[^\"]\"",
289  name, params, where_used, comment) != 4) {
290  G_warning(_("Error in datum table file <%s>, line %d"), file, line);
291  continue;
292  }
293 
294  if (G_strcasecmp(inputname, name) == 0) {
295  /* If the datum name in this line matches the one we are
296  * looking for, add an entry to the linked list */
297  if (current == NULL)
298  current = outputlist =
299  G_malloc(sizeof(struct gpj_datum_transform_list));
300  else
301  current = current->next =
302  G_malloc(sizeof(struct gpj_datum_transform_list));
303  current->params = G_store(params);
304  current->where_used = G_store(where_used);
305  current->comment = G_store(comment);
306  count++;
307  current->count = count;
308  current->next = NULL;
309  }
310  }
311 
312  fclose(fd);
313 
314  return outputlist;
315 }
316 
317 /**
318  * \brief Free the memory used by a gpj_datum_transform_list struct
319  *
320  * \param item gpj_datum_transform_list struct to be freed
321  **/
322 
324 {
325  G_free(item->params);
326  G_free(item->where_used);
327  G_free(item->comment);
328  G_free(item);
329  return;
330 }
331 
332 /**
333  * \brief Read the current GRASS datum.table from disk and store in
334  * memory
335  *
336  * The datum information is stored in a datum_list linked list structure.
337  *
338  * \return Pointer to first datum_list element in linked list, or NULL
339  * if unable to open datum.table file
340  **/
341 
342 struct datum_list *read_datum_table(void)
343 {
344  FILE *fd;
345  char file[GPATH_MAX];
346  char buf[4096];
347  int line;
348  struct datum_list *current = NULL, *outputlist = NULL;
349 
350  sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
351 
352  fd = fopen(file, "r");
353  if (!fd) {
354  G_warning(_("Unable to open datum table file <%s>"), file);
355  return NULL;
356  }
357 
358  for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
359  char name[100], descr[1024], ellps[100];
360  double dx, dy, dz;
361 
362  G_strip(buf);
363  if (*buf == '\0' || *buf == '#')
364  continue;
365 
366  if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf", name,
367  descr, ellps, &dx, &dy, &dz) != 6) {
368  G_warning(_("Error in datum table file <%s>, line %d"), file, line);
369  continue;
370  }
371 
372  if (current == NULL)
373  current = outputlist = G_malloc(sizeof(struct datum_list));
374  else
375  current = current->next = G_malloc(sizeof(struct datum_list));
376  current->name = G_store(name);
377  current->longname = G_store(descr);
378  current->ellps = G_store(ellps);
379  current->dx = dx;
380  current->dy = dy;
381  current->dz = dz;
382  current->next = NULL;
383  }
384 
385  fclose(fd);
386 
387  return outputlist;
388 }
389 
390 /**
391  * \brief Free the memory used for the strings in a gpj_datum struct
392  *
393  * \param dstruct gpj_datum struct to be freed
394  **/
395 
396 void GPJ_free_datum(struct gpj_datum *dstruct)
397 {
398  G_free(dstruct->name);
399  G_free(dstruct->longname);
400  G_free(dstruct->ellps);
401  return;
402 }
403 
404 /**
405  * \brief Free the memory used by a datum_list linked list structure
406  *
407  * \param dstruct datum_list struct to be freed
408  **/
409 
410 void free_datum_list(struct datum_list *dstruct)
411 {
412  struct datum_list *old;
413 
414  while (dstruct != NULL) {
415  G_free(dstruct->name);
416  G_free(dstruct->longname);
417  G_free(dstruct->ellps);
418  old = dstruct;
419  dstruct = old->next;
420  G_free(old);
421  }
422 
423  return;
424 }
#define NULL
Definition: ccmath.h:32
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:65
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
Definition: get_projinfo.c:61
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_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
int G_asprintf(char **, const char *,...) __attribute__((format(printf
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
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define GPATH_MAX
Definition: gis.h:194
#define _(str)
Definition: glocale.h:10
#define DATUMTABLE
Definition: gprojects.h:65
#define DATUMTRANSFORMTABLE
Definition: gprojects.h:66
int count
#define file
const char * name
Definition: named_colr.c:6
int GPJ_get_default_datum_params_by_name(const char *name, char **params)
"Last resort" function to retrieve a "default" set of datum parameters for a datum (N....
Definition: proj/datum.c:86
void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
Free the memory used by a gpj_datum_transform_list struct.
Definition: proj/datum.c:323
void GPJ_free_datum(struct gpj_datum *dstruct)
Free the memory used for the strings in a gpj_datum struct.
Definition: proj/datum.c:396
struct gpj_datum_transform_list * GPJ_get_datum_transform_by_name(const char *inputname)
Internal function to find all possible sets of transformation parameters for a particular datum.
Definition: proj/datum.c:237
void free_datum_list(struct datum_list *dstruct)
Free the memory used by a datum_list linked list structure.
Definition: proj/datum.c:410
int GPJ__get_datum_params(const struct Key_Value *projinfo, char **datumname, char **params)
Extract the datum transformation-related parameters from a set of general PROJ_INFO parameters.
Definition: proj/datum.c:173
int GPJ_get_datum_by_name(const char *name, struct gpj_datum *dstruct)
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
int GPJ_get_datum_params(char **name, char **params)
Extract the datum transformation-related parameters for the current location.
Definition: proj/datum.c:135
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
Definition: gis.h:525
struct gpj_datum_transform_list * next
Definition: gprojects.h:102
double dz
Definition: gprojects.h:87
char * longname
Definition: gprojects.h:86
double dy
Definition: gprojects.h:87
char * ellps
Definition: gprojects.h:86
double dx
Definition: gprojects.h:87
char * name
Definition: gprojects.h:86
Definition: manage.h:4