1 /*
2  ****************************************************************************
3  *
4  * MODULE:       gis library
5  * AUTHOR(S):    Andreas Lange - andreas.lange@rhein-main.de
6  *               Paul Kelly - paul-grass@stjohnspoint.co.uk
7  * PURPOSE:      provide functions for reading datum parameters from the
8  *               location database.
9  * COPYRIGHT:    (C) 2000, 2003 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 
17 #define DATUMTABLE "/etc/proj/datum.table"
18 
19 #include <unistd.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <stdlib.h>
23 
24 #include <grass/gis.h>
25 #include <grass/glocale.h>
26 
27 static struct table
28 {
29     struct datum
30     {
31 	char *name;		/* Short Name / acronym of map datum */
32 	char *descr;		/* Long Name for map datum */
33 	char *ellps;		/* acronym for ellipsoid used with this datum */
34 	double dx;		/* delta x */
35 	double dy;		/* delta y */
36 	double dz;		/* delta z */
37     } *datums;
38     int size;
39     int count;
40     int initialized;
41 } table;
42 
43 static int compare_table_names(const void *, const void *);
44 
G_get_datum_by_name(const char * name)45 int G_get_datum_by_name(const char *name)
46 {
47     int i;
48 
49     G_read_datum_table();
50 
51     for (i = 0; i < table.count; i++)
52 	if (G_strcasecmp(name, table.datums[i].name) == 0)
53 	    return i;
54 
55     return -1;
56 }
57 
G_datum_name(int n)58 const char *G_datum_name(int n)
59 {
60     G_read_datum_table();
61 
62     if (n < 0 || n >= table.count)
63 	return NULL;
64 
65     return table.datums[n].name;
66 }
67 
G_datum_description(int n)68 const char *G_datum_description(int n)
69 {
70     G_read_datum_table();
71 
72     if (n < 0 || n >= table.count)
73 	return NULL;
74 
75     return table.datums[n].descr;
76 }
77 
G_datum_ellipsoid(int n)78 const char *G_datum_ellipsoid(int n)
79 {
80     G_read_datum_table();
81 
82     if (n < 0 || n >= table.count)
83 	return NULL;
84 
85     return table.datums[n].ellps;
86 }
87 
88 /***********************************************************
89  *  G_get_datumparams_from_projinfo(projinfo, datumname, params)
90  *     struct Key_Value *projinfo Set of key_value pairs containing
91  *                       projection information in PROJ_INFO file
92  *                       format
93  *     char *datumname   Pointer into which a string containing
94  *                       the datum name (if present) will be
95  *                       placed.
96  *     char *params      Pointer into which a string containing
97  *                       the datum parameters (if present) will
98  *                       be placed.
99  *
100  *  Extract the datum transformation-related parameters from a
101  *  set of general PROJ_INFO parameters.
102  *  This function can be used to test if a location set-up
103  *  supports datum transformation.
104  *
105  *  returns: -1 error or no datum information found,
106  *           1 only datum name found, 2 params found
107  ************************************************************/
108 
G_get_datumparams_from_projinfo(const struct Key_Value * projinfo,char * datumname,char * params)109 int G_get_datumparams_from_projinfo(const struct Key_Value *projinfo,
110 				    char *datumname, char *params)
111 {
112     int returnval = -1;
113 
114     if (NULL != G_find_key_value("datum", projinfo)) {
115 	sprintf(datumname, "%s", G_find_key_value("datum", projinfo));
116 	returnval = 1;
117     }
118 
119     if (G_find_key_value("datumparams", projinfo) != NULL) {
120 	sprintf(params, "%s", G_find_key_value("datumparams", projinfo));
121 	returnval = 2;
122     }
123     else if (G_find_key_value("nadgrids", projinfo) != NULL) {
124 	sprintf(params, "nadgrids=%s",
125 		G_find_key_value("nadgrids", projinfo));
126 	returnval = 2;
127     }
128     else if (G_find_key_value("towgs84", projinfo) != NULL) {
129 	sprintf(params, "towgs84=%s", G_find_key_value("towgs84", projinfo));
130 	returnval = 2;
131     }
132     else if (G_find_key_value("dx", projinfo) != NULL
133 	     && G_find_key_value("dy", projinfo) != NULL
134 	     && G_find_key_value("dz", projinfo) != NULL) {
135 	sprintf(params, "towgs84=%s,%s,%s",
136 		G_find_key_value("dx", projinfo),
137 		G_find_key_value("dy", projinfo),
138 		G_find_key_value("dz", projinfo));
139 	returnval = 2;
140     }
141 
142     return returnval;
143 
144 }
145 
G_read_datum_table(void)146 void G_read_datum_table(void)
147 {
148     FILE *fd;
149     char file[GPATH_MAX];
150     char buf[1024];
151     int line;
152 
153     if (G_is_initialized(&table.initialized))
154 	return;
155 
156     sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);
157 
158     fd = fopen(file, "r");
159     if (!fd) {
160 	G_warning(_("unable to open datum table file: %s"), file);
161 	G_initialize_done(&table.initialized);
162 	return;
163     }
164 
165     for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
166 	char name[100], descr[100], ellps[100];
167 	struct datum *t;
168 
169 	G_strip(buf);
170 	if (*buf == '\0' || *buf == '#')
171 	    continue;
172 
173 	if (table.count >= table.size) {
174 	    table.size += 50;
175 	    table.datums = G_realloc(table.datums, table.size * sizeof(struct datum));
176 	}
177 
178 	t = &table.datums[table.count];
179 
180 	if (sscanf(buf, "%s \"%99[^\"]\" %s dx=%lf dy=%lf dz=%lf",
181 		   name, descr, ellps, &t->dx, &t->dy, &t->dz) != 6) {
182 	    G_warning(_("error in datum table file, line %d"), line);
183 	    continue;
184 	}
185 
186 	t->name = G_store(name);
187 	t->descr = G_store(descr);
188 	t->ellps = G_store(ellps);
189 
190 	table.count++;
191     }
192 
193     qsort(table.datums, table.count, sizeof(struct datum), compare_table_names);
194 
195     G_initialize_done(&table.initialized);
196 }
197 
compare_table_names(const void * aa,const void * bb)198 static int compare_table_names(const void *aa, const void *bb)
199 {
200     const struct datum *a = aa;
201     const struct datum *b = bb;
202 
203     return G_strcasecmp(a->name, b->name);
204 }
205