GRASS GIS 8 Programmer's Manual 8.2.1RC1(2022)-exported
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
37int 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
85int 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
135int 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
173int 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
236struct gpj_datum_transform_list *GPJ_get_datum_transform_by_name(const char
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
325void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
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
344struct 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
402void 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
416void 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}
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
int G_asprintf(char **out, const char *fmt,...)
Definition: asprintf.c:70
#define NULL
Definition: ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
Definition: get_projinfo.c:61
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: gis/datum.c:17
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition: gisbase.c:41
int count
void G_free_key_value(struct Key_Value *kv)
Free allocated Key_Value structure.
Definition: key_value1.c:103
const char * G_find_key_value(const char *key, const struct Key_Value *kv)
Find given key (case sensitive)
Definition: key_value1.c:84
#define file
const char * name
Definition: named_colr.c:7
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
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
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
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
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(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:37
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:344
struct list * list
Definition: read_list.c:24
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:47
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition: strings.c:300