GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
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
5location database
6
7 \author Andreas Lange <andreas.lange rhein-main.de>, Paul Kelly <paul-grass
8stjohnspoint.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
38int 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
86int 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
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, 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
236struct gpj_datum_transform_list *
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
323void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
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
342struct 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
396void 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
410void 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}
void G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
int G_asprintf(char **out, const char *fmt,...)
Definition asprintf.c:69
#define NULL
Definition ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition debug.c:66
struct Key_Value * G_get_projinfo(void)
Gets projection information for location.
int G_getl2(char *buf, int n, FILE *fd)
Gets a line of text from a file of any pedigree.
Definition getl.c:65
#define DATUMTABLE
Definition gis/datum.c:17
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition gis/error.c:203
const char * G_gisbase(void)
Get full path name of the top level module directory.
Definition gisbase.c:39
int count
void G_free_key_value(struct Key_Value *kv)
Free allocated Key_Value structure.
Definition key_value1.c:104
const char * G_find_key_value(const char *key, const struct Key_Value *kv)
Find given key (case sensitive)
Definition key_value1.c:85
#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
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