GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
proj/datum.c
Go to the documentation of this file.
1 
2 /**
3  \file lib/proj/datum.c
4 
5  \brief GProj library - Functions for reading datum parameters from the location database
6 
7  \author Andreas Lange <andreas.lange rhein-main.de>, Paul Kelly <paul-grass stjohnspoint.co.uk>
8 
9  (C) 2003-2008 by the GRASS Development Team
10 
11  This program is free software under the GNU General Public
12  License (>=v2). Read the file COPYING that comes with GRASS
13  for details.
14 **/
15 
16 #include <unistd.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <stdlib.h>
20 
21 #include <grass/gis.h>
22 #include <grass/glocale.h>
23 #include <grass/gprojects.h>
24 #include "local_proto.h"
25 
26 /**
27  * \brief Look up a string in datum.table file to see if it is a valid datum
28  * name and if so place its information into a gpj_datum struct
29  *
30  * \param name String containing datum name to look up
31  * \param dstruct gpj_datum struct into which datum parameters will be placed
32  * if found
33  *
34  * \return 1 if datum found, -1 if not
35  **/
36 
37 int GPJ_get_datum_by_name(const char *name, struct gpj_datum *dstruct)
38 {
39  struct datum_list *list, *listhead;
40 
41  list = listhead = read_datum_table();
42 
43  while (list != NULL) {
44  if (G_strcasecmp(name, list->name) == 0) {
45  dstruct->name = G_store(list->name);
46  dstruct->longname = G_store(list->longname);
47  dstruct->ellps = G_store(list->ellps);
48  dstruct->dx = list->dx;
49  dstruct->dy = list->dy;
50  dstruct->dz = list->dz;
51  free_datum_list(listhead);
52  return 1;
53  }
54  list = list->next;
55  }
56  free_datum_list(listhead);
57  return -1;
58 }
59 
60 /**
61  * \brief "Last resort" function to retrieve a "default" set of datum
62  * parameters for a datum (N.B. there really is no such thing as a
63  * catch-all default!)
64  *
65  * Kind of a "last resort" function as there really is no such thing
66  * as a default set of datum transformation parameters. Only should
67  * really be used where user interaction to choose a set of parameters
68  * is not desirable. Use of this function is not likely to result in
69  * selection of the optimum set of datum transformation parameters
70  * for the location
71  *
72  * \param name String containing GRASS datum name for which default
73  * parameters are to be retrieved
74  *
75  * \param params Pointer to a pointer which will have memory
76  * allocated and into which a string containing
77  * the datum parameters (if present) will
78  * be placed
79  *
80  * \return The number of possible parameter sets GRASS knows
81  * about for this datum
82  *
83  **/
84 
85 int GPJ_get_default_datum_params_by_name(const char *name, char **params)
86 {
87  struct gpj_datum_transform_list *list, *old;
88  int count = 0;
89 
91 
92  if (list == NULL) {
93  *params = NULL;
94  return -1;
95  }
96 
97  /* Take the first parameter set in the list as the default
98  * (will normally be a 3-parameter transformation) */
99  *params = G_store(list->params);
100 
101  while (list != NULL) {
102  count++;
103  old = list;
104  list = list->next;
106  }
107 
108  return count;
109 
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,
174  char **datumname, 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>", G_find_key_value("datum", projinfo));
181  returnval = 1;
182  }
183  else
184  *datumname = NULL;
185 
186  if (G_find_key_value("datumparams", projinfo) != NULL) {
187  *params = G_store(G_find_key_value("datumparams", projinfo));
188  G_debug(3, "GPJ__get_datum_params: datumparams: <%s>", G_find_key_value("datumparams", projinfo));
189  returnval = 2;
190  }
191  else if (G_find_key_value("nadgrids", projinfo) != NULL) {
192  /* 1. beware of '@', do not create something like
193  * /usr/share/proj/@null, correct is @null or
194  * @/usr/share/proj/null
195  * 2. do not add path to the grid, there might already be a
196  * path, and it is safer to use pj_set_finder with PROJ.4 in
197  * datum.c */
198 
199  G_asprintf(params, "nadgrids=%s", G_find_key_value("nadgrids", projinfo));
200 
201  returnval = 2;
202  }
203  else if (G_find_key_value("towgs84", projinfo) != NULL) {
204  G_asprintf(params, "towgs84=%s",
205  G_find_key_value("towgs84", projinfo));
206  returnval = 2;
207  }
208  else if (G_find_key_value("dx", projinfo) != NULL
209  && G_find_key_value("dy", projinfo) != NULL
210  && G_find_key_value("dz", projinfo) != NULL) {
211  G_asprintf(params, "towgs84=%s,%s,%s",
212  G_find_key_value("dx", projinfo),
213  G_find_key_value("dy", projinfo),
214  G_find_key_value("dz", projinfo));
215  returnval = 2;
216  }
217  else
218  *params = NULL;
219 
220  return returnval;
221 
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  *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,
291  line);
292  continue;
293  }
294 
295  if (G_strcasecmp(inputname, name) == 0) {
296  /* If the datum name in this line matches the one we are
297  * looking for, add an entry to the linked list */
298  if (current == NULL)
299  current = outputlist =
300  G_malloc(sizeof(struct gpj_datum_transform_list));
301  else
302  current = current->next =
303  G_malloc(sizeof(struct gpj_datum_transform_list));
304  current->params = G_store(params);
305  current->where_used = G_store(where_used);
306  current->comment = G_store(comment);
307  count++;
308  current->count = count;
309  current->next = NULL;
310  }
311  }
312 
313  fclose(fd);
314 
315  return outputlist;
316 
317 }
318 
319 /**
320  * \brief Free the memory used by a gpj_datum_transform_list struct
321  *
322  * \param item gpj_datum_transform_list struct to be freed
323  **/
324 
326 {
327  G_free(item->params);
328  G_free(item->where_used);
329  G_free(item->comment);
330  G_free(item);
331  return;
332 }
333 
334 /**
335  * \brief Read the current GRASS datum.table from disk and store in
336  * memory
337  *
338  * The datum information is stored in a datum_list linked list structure.
339  *
340  * \return Pointer to first datum_list element in linked list, or NULL
341  * if unable to open datum.table file
342  **/
343 
344 struct datum_list *read_datum_table(void)
345 {
346  FILE *fd;
347  char file[GPATH_MAX];
348  char buf[4096];
349  int line;
350  struct datum_list *current = NULL, *outputlist = NULL;
351  int count = 0;
352 
353  sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
354 
355  fd = fopen(file, "r");
356  if (!fd) {
357  G_warning(_("Unable to open datum table file <%s>"), file);
358  return NULL;
359  }
360 
361  for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
362  char name[100], descr[1024], ellps[100];
363  double dx, dy, dz;
364 
365  G_strip(buf);
366  if (*buf == '\0' || *buf == '#')
367  continue;
368 
369  if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf",
370  name, descr, ellps, &dx, &dy, &dz) != 6) {
371  G_warning(_("Error in datum table file <%s>, line %d"), file,
372  line);
373  continue;
374  }
375 
376  if (current == NULL)
377  current = outputlist = G_malloc(sizeof(struct datum_list));
378  else
379  current = current->next = G_malloc(sizeof(struct datum_list));
380  current->name = G_store(name);
381  current->longname = G_store(descr);
382  current->ellps = G_store(ellps);
383  current->dx = dx;
384  current->dy = dy;
385  current->dz = dz;
386  current->next = NULL;
387 
388  count++;
389  }
390 
391  fclose(fd);
392 
393  return outputlist;
394 }
395 
396 /**
397  * \brief Free the memory used for the strings in a gpj_datum struct
398  *
399  * \param dstruct gpj_datum struct to be freed
400  **/
401 
402 void GPJ_free_datum(struct gpj_datum *dstruct)
403 {
404  G_free(dstruct->name);
405  G_free(dstruct->longname);
406  G_free(dstruct->ellps);
407  return;
408 }
409 
410 /**
411  * \brief Free the memory used by a datum_list linked list structure
412  *
413  * \param dstruct datum_list struct to be freed
414  **/
415 
416 void free_datum_list(struct datum_list *dstruct)
417 {
418  struct datum_list *old;
419 
420  while (dstruct != NULL) {
421  G_free(dstruct->name);
422  G_free(dstruct->longname);
423  G_free(dstruct->ellps);
424  old = dstruct;
425  dstruct = old->next;
426  G_free(old);
427  }
428 
429  return;
430 }
int G_getl2(char *, int, FILE *)
Gets a line of text from a file of any pedigree.
Definition: getl.c:64
#define G_malloc(n)
Definition: defs/gis.h:112
#define DATUMTRANSFORMTABLE
Definition: gprojects.h:64
void GPJ_free_datum(struct gpj_datum *dstruct)
Free the memory used for the strings in a gpj_datum struct.
Definition: proj/datum.c:402
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
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
Definition: get_projinfo.c:61
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:325
double dx
Definition: gprojects.h:87
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
int count
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
#define NULL
Definition: ccmath.h:32
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:236
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:37
char * name
Definition: gprojects.h:86
#define DATUMTABLE
Definition: gprojects.h:63
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition: strings.c:47
void free_datum_list(struct datum_list *dstruct)
Free the memory used by a datum_list linked list structure.
Definition: proj/datum.c:416
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 list * list
Definition: read_list.c:24
char * ellps
Definition: gprojects.h:86
char * longname
Definition: gprojects.h:86
#define GPATH_MAX
Definition: gis.h:180
struct datum_list * read_datum_table(void)
Read the current GRASS datum.table from disk and store in memory.
Definition: proj/datum.c:344
Definition: gis.h:512
double dz
Definition: gprojects.h:87
double dy
Definition: gprojects.h:87
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
void G_warning(const char *,...) __attribute__((format(printf
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:85
struct gpj_datum_transform_list * next
Definition: gprojects.h:103
#define file
#define _(str)
Definition: glocale.h:10
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
int G_asprintf(char **, const char *,...) __attribute__((format(printf
const char * name
Definition: named_colr.c:7
int G_debug(int, const char *,...) __attribute__((format(printf
void G_free_key_value(struct Key_Value *)
Free allocated Key_Value structure.
Definition: key_value1.c:103
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
Definition: key_value1.c:84