GRASS GIS 7 Programmer's Manual  7.5.svn(2018)-r72255
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 {
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  const char *projshare = getenv("GRASS_PROJSHARE");
193 
194  if (!projshare) {
195  G_warning(_("Failed to detect nadgrids path, GRASS_PROJSHARE not defined"));
196  returnval = -1;
197  }
198  else {
199  G_asprintf(params, "nadgrids=%s%c%s", projshare, HOST_DIRSEP,
200  G_find_key_value("nadgrids", projinfo));
201  returnval = 2;
202  }
203  }
204  else if (G_find_key_value("towgs84", projinfo) != NULL) {
205  G_asprintf(params, "towgs84=%s",
206  G_find_key_value("towgs84", projinfo));
207  returnval = 2;
208  }
209  else if (G_find_key_value("dx", projinfo) != NULL
210  && G_find_key_value("dy", projinfo) != NULL
211  && G_find_key_value("dz", projinfo) != NULL) {
212  G_asprintf(params, "towgs84=%s,%s,%s",
213  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 /**
226  * \brief Internal function to find all possible sets of
227  * transformation parameters for a particular datum
228  *
229  * \param inputname String containing the datum name we
230  * are going to look up parameters for
231  *
232  * \return Pointer to struct gpj_datum_transform_list (a linked
233  * list containing transformation parameters),
234  * or NULL if no suitable parameters were found.
235  **/
236 
238  *inputname)
239 {
240  FILE *fd;
241  char file[GPATH_MAX];
242  char buf[1024];
243  int line;
244  struct gpj_datum_transform_list *current = NULL, *outputlist = NULL;
245  struct gpj_datum dstruct;
246  int count = 0;
247 
248  GPJ_get_datum_by_name(inputname, &dstruct);
249  if (dstruct.dx < 99999 && dstruct.dy < 99999 && dstruct.dz < 99999) {
250  /* Include the old-style dx dy dz parameters from datum.table at the
251  * start of the list, unless these have been set to all 99999 to
252  * indicate only entries in datumtransform.table should be used */
253  if (current == NULL)
254  current = outputlist =
255  G_malloc(sizeof(struct gpj_datum_transform_list));
256  else
257  current = current->next =
258  G_malloc(sizeof(struct gpj_datum_transform_list));
259  G_asprintf(&(current->params), "towgs84=%.3f,%.3f,%.3f", dstruct.dx,
260  dstruct.dy, dstruct.dz);
261  G_asprintf(&(current->where_used), "whole %s region", inputname);
262  G_asprintf(&(current->comment),
263  "Default 3-Parameter Transformation (May not be optimum for "
264  "older datums; use this only if no more appropriate options "
265  "are available.)");
266  count++;
267  current->count = count;
268  current->next = NULL;
269  }
270  GPJ_free_datum(&dstruct);
271 
272  /* Now check for additional parameters in datumtransform.table */
273 
274  sprintf(file, "%s%s", G_gisbase(), DATUMTRANSFORMTABLE);
275 
276  fd = fopen(file, "r");
277  if (!fd) {
278  G_warning(_("Unable to open datum table file <%s>"), file);
279  return outputlist;
280  }
281 
282  for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
283  char name[100], params[1024], where_used[1024], comment[1024];
284 
285  G_strip(buf);
286  if (*buf == '\0' || *buf == '#')
287  continue;
288 
289  if (sscanf(buf, "%99s \"%1023[^\"]\" \"%1023[^\"]\" \"%1023[^\"]\"",
290  name, params, where_used, comment) != 4) {
291  G_warning(_("Error in datum table file <%s>, line %d"), file,
292  line);
293  continue;
294  }
295 
296  if (G_strcasecmp(inputname, name) == 0) {
297  /* If the datum name in this line matches the one we are
298  * looking for, add an entry to the linked list */
299  if (current == NULL)
300  current = outputlist =
301  G_malloc(sizeof(struct gpj_datum_transform_list));
302  else
303  current = current->next =
304  G_malloc(sizeof(struct gpj_datum_transform_list));
305  current->params = G_store(params);
306  current->where_used = G_store(where_used);
307  current->comment = G_store(comment);
308  count++;
309  current->count = count;
310  current->next = NULL;
311  }
312  }
313 
314  fclose(fd);
315 
316  return outputlist;
317 
318 }
319 
320 /**
321  * \brief Free the memory used by a gpj_datum_transform_list struct
322  *
323  * \param item gpj_datum_transform_list struct to be freed
324  **/
325 
327 {
328  G_free(item->params);
329  G_free(item->where_used);
330  G_free(item->comment);
331  G_free(item);
332  return;
333 }
334 
335 /**
336  * \brief Read the current GRASS datum.table from disk and store in
337  * memory
338  *
339  * The datum information is stored in a datum_list linked list structure.
340  *
341  * \return Pointer to first datum_list element in linked list, or NULL
342  * if unable to open datum.table file
343  **/
344 
345 struct datum_list *read_datum_table(void)
346 {
347  FILE *fd;
348  char file[GPATH_MAX];
349  char buf[4096];
350  int line;
351  struct datum_list *current = NULL, *outputlist = NULL;
352  int count = 0;
353 
354  sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
355 
356  fd = fopen(file, "r");
357  if (!fd) {
358  G_warning(_("Unable to open datum table file <%s>"), file);
359  return NULL;
360  }
361 
362  for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
363  char name[100], descr[1024], ellps[100];
364  double dx, dy, dz;
365 
366  G_strip(buf);
367  if (*buf == '\0' || *buf == '#')
368  continue;
369 
370  if (sscanf(buf, "%s \"%1023[^\"]\" %s dx=%lf dy=%lf dz=%lf",
371  name, descr, ellps, &dx, &dy, &dz) != 6) {
372  G_warning(_("Error in datum table file <%s>, line %d"), file,
373  line);
374  continue;
375  }
376 
377  if (current == NULL)
378  current = outputlist = G_malloc(sizeof(struct datum_list));
379  else
380  current = current->next = G_malloc(sizeof(struct datum_list));
381  current->name = G_store(name);
382  current->longname = G_store(descr);
383  current->ellps = G_store(ellps);
384  current->dx = dx;
385  current->dy = dy;
386  current->dz = dz;
387  current->next = NULL;
388 
389  count++;
390  }
391 
392  fclose(fd);
393 
394  return outputlist;
395 }
396 
397 /**
398  * \brief Free the memory used for the strings in a gpj_datum struct
399  *
400  * \param dstruct gpj_datum struct to be freed
401  **/
402 
403 void GPJ_free_datum(struct gpj_datum *dstruct)
404 {
405  G_free(dstruct->name);
406  G_free(dstruct->longname);
407  G_free(dstruct->ellps);
408  return;
409 }
410 
411 /**
412  * \brief Free the memory used by a datum_list linked list structure
413  *
414  * \param dstruct datum_list struct to be freed
415  **/
416 
417 void free_datum_list(struct datum_list *dstruct)
418 {
419  struct datum_list *old;
420 
421  while (dstruct != NULL) {
422  G_free(dstruct->name);
423  G_free(dstruct->longname);
424  G_free(dstruct->ellps);
425  old = dstruct;
426  dstruct = old->next;
427  G_free(old);
428  }
429 
430  return;
431 }
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:46
const char * G_find_key_value(const char *key, const struct Key_Value *kv)
Find given key (case sensitive)
Definition: key_value1.c:84
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
#define DATUMTRANSFORMTABLE
Definition: gprojects.h:29
void GPJ_free_datum(struct gpj_datum *dstruct)
Free the memory used for the strings in a gpj_datum struct.
Definition: proj/datum.c:403
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
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition: strings.c:258
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:326
double dx
Definition: gprojects.h:44
int old
Definition: raster3d/cats.c:84
int count
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:86
int G_asprintf(char **out, const char *fmt,...)
Definition: asprintf.c:70
#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:237
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
void G_free_key_value(struct Key_Value *kv)
Free allocated Key_Value structure.
Definition: key_value1.c:103
fd
Definition: d/range.c:69
#define HOST_DIRSEP
Definition: gis.h:194
char * name
Definition: gprojects.h:43
int G_getl2(char *buf, int n, FILE *fd)
Gets a line of text from a file of any pedigree.
Definition: getl.c:64
#define DATUMTABLE
Definition: gprojects.h:28
void free_datum_list(struct datum_list *dstruct)
Free the memory used by a datum_list linked list structure.
Definition: proj/datum.c:417
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
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
char * ellps
Definition: gprojects.h:43
fclose(fd)
char * longname
Definition: gprojects.h:43
#define GPATH_MAX
Definition: gis.h:151
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
Definition: get_projinfo.c:58
struct datum_list * read_datum_table(void)
Read the current GRASS datum.table from disk and store in memory.
Definition: proj/datum.c:345
Definition: gis.h:479
double dz
Definition: gprojects.h:44
double dy
Definition: gprojects.h:44
int GPJ_get_default_datum_params_by_name(const char *name, char **params)
&quot;Last resort&quot; function to retrieve a &quot;default&quot; set of datum parameters for a datum (N...
Definition: proj/datum.c:85
struct gpj_datum_transform_list * next
Definition: gprojects.h:59
#define file
#define _(str)
Definition: glocale.h:13
const char * name
Definition: named_colr.c:7
char * getenv()
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204