1 /*!
2   \file lib/gis/proj3.c
3 
4   \brief GIS Library - Projection support (database)
5 
6   (C) 2001-2014 by the GRASS Development Team
7 
8   This program is free software under the GNU General Public License
9   (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11   \author Original author CERL
12  */
13 
14 /* TODO: the G_database_*() functions should be renamed to G_location_*()
15  * because they apply to a GRASS location, not to a GRASS database */
16 
17 #include <string.h>
18 #include <grass/gis.h>
19 #include <grass/glocale.h>
20 
21 static const char *lookup_proj(const char *);
22 static const char *lookup_units(const char *);
23 static const char *lookup_epsg();
24 static int equal(const char *, const char *);
25 static int lower(char);
26 
27 static int initialized;
28 static struct Key_Value *proj_info, *proj_units, *proj_epsg;
29 
init(void)30 static void init(void)
31 {
32     if (G_is_initialized(&initialized))
33 	return;
34 
35     proj_info = G_get_projinfo();
36     proj_units = G_get_projunits();
37     proj_epsg = G_get_projepsg();
38 
39     G_initialize_done(&initialized);
40 }
41 
42 /*!
43   \brief Get units (localized) name for the current location
44 
45   Returns a string describing the database grid units. It returns a
46   plural form (eg. 'feet') if <i>plural</i> is non-zero. Otherwise it
47   returns a singular form (eg. 'foot').
48 
49   \param plural plural form if non-zero
50 
51   \return localized units name
52 */
G_database_unit_name(int plural)53 const char *G_database_unit_name(int plural)
54 {
55     int units;
56     units = G_database_unit();
57     return G_get_units_name(units, plural, FALSE);
58 }
59 
60 /*!
61   \brief Get units id for the current location
62 
63   \return units id
64 */
G_database_unit()65 int G_database_unit()
66 {
67     int units;
68     const char *name;
69 
70     units = G_projection_units(G_projection());
71 
72     if (units == U_UNDEFINED) {
73 	name = lookup_units("unit");
74 	if (!name)
75 	    return U_UNKNOWN;
76 
77 	if (strcasecmp(name, "meter") == 0 || strcasecmp(name, "metre") == 0
78             || strcasecmp(name, "meters") == 0 || strcasecmp(name, "metres") == 0)
79 	    units = U_METERS;
80 	else if (strcasecmp(name, "kilometer") == 0 || strcasecmp(name, "kilometre") == 0
81                  || strcasecmp(name, "kilometers") == 0 || strcasecmp(name, "kilometres") == 0)
82 	    units = U_KILOMETERS;
83 	else if (strcasecmp(name, "acre") == 0 || strcasecmp(name, "acres") == 0)
84 	    units = U_ACRES;
85 	else if (strcasecmp(name, "hectare") == 0 || strcasecmp(name, "hectares") == 0)
86 	    units = U_HECTARES;
87 	else if (strcasecmp(name, "mile") == 0 || strcasecmp(name, "miles") == 0)
88 	    units = U_MILES;
89 	else if (strcasecmp(name, "foot") == 0 || strcasecmp(name, "feet") == 0)
90 	    units = U_FEET;
91 	else if (strcasecmp(name, "foot_us") == 0 || strcasecmp(name, "foot_uss") == 0)
92 	    units = U_USFEET;
93 	else if (strcasecmp(name, "degree") == 0 || strcasecmp(name, "degrees") == 0)
94 	    units = U_DEGREES;
95 	else
96 	    units = U_UNKNOWN;
97     }
98     return units;
99 }
100 
101 /*!
102   \brief Query cartographic projection for the current location
103 
104   Returns a pointer to a string which is a printable name for
105   projection code <i>proj</i> (as returned by G_projection). Returns
106   NULL if <i>proj</i> is not a valid projection.
107 
108   \return projection name
109 */
G_database_projection_name(void)110 const char *G_database_projection_name(void)
111 {
112     int n;
113     const char *name;
114 
115     switch (n = G_projection()) {
116     case PROJECTION_XY:
117     case PROJECTION_UTM:
118     case PROJECTION_LL:
119 	return G_projection_name(n);
120     }
121 
122     name = lookup_proj("name");
123     if (!name)
124 	return _("Unknown projection");
125 
126     return name;
127 }
128 
129 /*!
130   \brief Conversion to meters
131 
132   Returns a factor which converts the grid unit to meters (by
133   multiplication). If the database is not metric (eg. imagery) then
134   0.0 is returned.
135 
136   \return value
137 */
G_database_units_to_meters_factor(void)138 double G_database_units_to_meters_factor(void)
139 {
140     const char *unit;
141     const char *buf;
142     double factor;
143     int n;
144 
145     /* TODO: sync with definitions in ../proj/units.table */
146     static const struct
147     {
148 	char *unit;
149 	double factor;
150     } table[] = {
151 	{"unit",  1.0},
152 	{"meter", 1.0},
153 	{"foot",  .3048},
154 	{"foot_us", 1200/3937.},
155 	{"inch", .0254},
156 	{NULL, 0.0}
157     };
158 
159     factor = 0.0;
160     buf = lookup_units("meters");
161     if (buf)
162 	sscanf(buf, "%lf", &factor);
163     if (factor <= 0.0) {
164 	unit = G_database_unit_name(0);
165 	for (n = 0; table[n].unit; n++)
166 	    if (equal(unit, table[n].unit)) {
167 		factor = table[n].factor;
168 		break;
169 	    }
170     }
171     return factor;
172 }
173 
174 /*!
175   \brief Get datum name for the current location
176 
177   Returns a pointer to the name of the map datum of the current
178   database. If there is no map datum explicitely associated with the
179   actual database, the standard map datum WGS84 is returned, on error
180   a NULL pointer is returned.
181 
182   \return datum name
183 */
G_database_datum_name(void)184 const char *G_database_datum_name(void)
185 {
186     const char *name;
187     char buf[256], params[256];
188     int datumstatus;
189 
190     name = lookup_proj("datum");
191     if (name)
192 	return name;
193     else if (!proj_info)
194 	return NULL;
195     else
196 	datumstatus = G_get_datumparams_from_projinfo(proj_info, buf, params);
197 
198     if (datumstatus == 2)
199 	return G_store(params);
200     else
201 	return NULL;
202 }
203 
204 /*!
205   \brief Get ellipsoid name for the current location
206 
207   \return pointer to valid name if ok
208   \return NULL on error
209 */
G_database_ellipse_name(void)210 const char *G_database_ellipse_name(void)
211 {
212     const char *name;
213 
214     name = lookup_proj("ellps");
215     if (!name) {
216 	char buf[256];
217 	double a, es;
218 
219 	G_get_ellipsoid_parameters(&a, &es);
220 	sprintf(buf, "a=%.16g es=%.16g", a, es);
221 	name = G_store(buf);
222     }
223 
224     /* strcpy (name, "Unknown ellipsoid"); */
225     return name;
226 }
227 
228 /*!
229   \brief Get EPGS code for the current location
230 
231   \return pointer to valid EPSG code on success
232   \return NULL on error
233 */
G_database_epsg_code(void)234 const char *G_database_epsg_code(void)
235 {
236     return lookup_epsg();
237 }
238 
lookup_proj(const char * key)239 const char *lookup_proj(const char *key)
240 {
241     init();
242     return G_find_key_value(key, proj_info);
243 }
244 
lookup_units(const char * key)245 const char *lookup_units(const char *key)
246 {
247     init();
248     return G_find_key_value(key, proj_units);
249 }
250 
lookup_epsg()251 const char *lookup_epsg()
252 {
253     init();
254     return G_find_key_value("epsg", proj_epsg);
255 }
256 
equal(const char * a,const char * b)257 int equal(const char *a, const char *b)
258 {
259     if (a == NULL || b == NULL)
260 	return a == b;
261     while (*a && *b)
262 	if (lower(*a++) != lower(*b++))
263 	    return 0;
264     if (*a || *b)
265 	return 0;
266     return 1;
267 }
268 
lower(char c)269 int lower(char c)
270 {
271     if (c >= 'A' && c <= 'Z')
272 	c += 'a' - 'A';
273     return c;
274 }
275