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