GRASS 8 Programmer's Manual 8.6.0dev(2026)-1d1e47ad9d
Loading...
Searching...
No Matches
make_loc.c
Go to the documentation of this file.
1/*!
2 * \file lib/gis/make_loc.c
3 *
4 * \brief GIS Library - Functions to create a new location
5 *
6 * Creates a new location automatically given a "Cell_head", PROJ_INFO
7 * and PROJ_UNITS information.
8 *
9 * (C) 2000-2013 by the GRASS Development Team
10 *
11 * This program is free software under the GNU General Public License
12 * (>=v2). Read the file COPYING that comes with GRASS for details.
13 *
14 * \author Frank Warmerdam
15 */
16
17#include <grass/gis.h>
18
19#include <stdlib.h>
20#include <string.h>
21#include <errno.h>
22#include <unistd.h>
23#include <sys/stat.h>
24#include <math.h>
25#include <grass/glocale.h>
26
27/*!
28 * \brief Create a new location
29 *
30 * This function creates a new location in the current database,
31 * initializes the projection, default window and current window.
32 *
33 * \param location_name Name of the new location. Should not include
34 * the full path, the location will be created within
35 * the current database.
36 * \param wind default window setting for the new location.
37 * All fields should be set in this
38 * structure, and care should be taken to ensure that
39 * the proj/zone fields match the definition in the
40 * proj_info parameter(see G_set_cellhd_from_projinfo()).
41 *
42 * \param proj_info projection definition suitable to write to the
43 * PROJ_INFO file, or NULL for PROJECTION_XY.
44 *
45 * \param proj_units projection units suitable to write to the PROJ_UNITS
46 * file, or NULL.
47 *
48 * \return 0 on success
49 * \return -1 to indicate a system error (check errno).
50 * \return -2 failed to create projection file (currently not used)
51 * \return -3 illegal name
52 */
53int G_make_location(const char *location_name, struct Cell_head *wind,
54 const struct Key_Value *proj_info,
55 const struct Key_Value *proj_units)
56{
57 char path[GPATH_MAX];
58
59 /* check if location name is legal */
61 return -3;
62
63 /* Try to create the location directory, under the gisdbase. */
64 snprintf(path, sizeof(path), "%s/%s", G_gisdbase(), location_name);
65 if (G_mkdir(path) != 0)
66 return -1;
67
68 /* Make the PERMANENT mapset. */
69 snprintf(path, sizeof(path), "%s/%s/%s", G_gisdbase(), location_name,
70 "PERMANENT");
71 if (G_mkdir(path) != 0) {
72 return -1;
73 }
74
75 /* make these the new current location and mapset */
76 G_setenv_nogisrc("LOCATION_NAME", location_name);
77 G_setenv_nogisrc("MAPSET", "PERMANENT");
78
79 /* Create the default, and current window files */
80 G_put_element_window(wind, "", "DEFAULT_WIND");
81 G_put_element_window(wind, "", "WIND");
82
83 /* Write out the PROJ_INFO, and PROJ_UNITS if available. */
84 if (proj_info != NULL) {
85 G_file_name(path, "", "PROJ_INFO", "PERMANENT");
86 G_write_key_value_file(path, proj_info);
87 }
88
89 if (proj_units != NULL) {
90 G_file_name(path, "", "PROJ_UNITS", "PERMANENT");
91 G_write_key_value_file(path, proj_units);
92 }
93
94 return 0;
95}
96
97/*!
98 * \brief Create a new location
99 *
100 * This function creates a new location in the current database,
101 * initializes the projection, default window and current window,
102 * and sets the EPSG code if present
103 *
104 * \param location_name Name of the new location. Should not include
105 * the full path, the location will be created within
106 * the current database.
107 * \param wind default window setting for the new location.
108 * All fields should be set in this
109 * structure, and care should be taken to ensure that
110 * the proj/zone fields match the definition in the
111 * proj_info parameter(see G_set_cellhd_from_projinfo()).
112 *
113 * \param proj_info projection definition suitable to write to the
114 * PROJ_INFO file, or NULL for PROJECTION_XY.
115 *
116 * \param proj_units projection units suitable to write to the PROJ_UNITS
117 * file, or NULL.
118 *
119 * \param proj_epsg EPSG code suitable to write to the PROJ_EPSG
120 * file, or NULL.
121 *
122 * \return 0 on success
123 * \return -1 to indicate a system error (check errno).
124 * \return -2 failed to create projection file (currently not used)
125 * \return -3 illegal name
126 */
127int G_make_location_epsg(const char *location_name, struct Cell_head *wind,
128 const struct Key_Value *proj_info,
129 const struct Key_Value *proj_units,
130 const struct Key_Value *proj_epsg)
131{
132 int ret;
133
134 ret = G_make_location(location_name, wind, proj_info, proj_units);
135
136 if (ret != 0)
137 return ret;
138
139 /* Write out the PROJ_EPSG if available. */
140 if (proj_epsg != NULL) {
141 char path[GPATH_MAX];
142
143 G_file_name(path, "", "PROJ_EPSG", "PERMANENT");
144 G_write_key_value_file(path, proj_epsg);
145 }
146
147 return 0;
148}
149
150/*!
151 * \brief Create a new location
152 *
153 * This function creates a new location in the current database,
154 * initializes the projection, default window and current window,
155 * and sets WKT, srid, and EPSG code if present
156 *
157 * \param location_name Name of the new location. Should not include
158 * the full path, the location will be created within
159 * the current database.
160 * \param wind default window setting for the new location.
161 * All fields should be set in this
162 * structure, and care should be taken to ensure that
163 * the proj/zone fields match the definition in the
164 * proj_info parameter(see G_set_cellhd_from_projinfo()).
165 *
166 * \param proj_info projection definition suitable to write to the
167 * PROJ_INFO file, or NULL for PROJECTION_XY.
168 *
169 * \param proj_units projection units suitable to write to the PROJ_UNITS
170 * file, or NULL.
171 *
172 * \param proj_srid Spatial reference ID suitable to write to the PROJ_SRID
173 * file, or NULL.
174 *
175 * \param proj_wkt WKT definition suitable to write to the PROJ_WKT
176 * file, or NULL.
177 *
178 * \return 0 on success
179 * \return -1 to indicate a system error (check errno).
180 * \return -2 failed to create projection file (currently not used)
181 * \return -3 illegal name
182 */
183int G_make_location_crs(const char *location_name, struct Cell_head *wind,
184 const struct Key_Value *proj_info,
185 const struct Key_Value *proj_units,
186 const char *proj_srid, const char *proj_wkt)
187{
188 int ret;
189
190 ret = G_make_location(location_name, wind, proj_info, proj_units);
191
192 if (ret != 0)
193 return ret;
194
195 /* Write out PROJ_SRID if srid is available. */
196 if (proj_srid != NULL) {
198 }
199
200 /* Write out PROJ_WKT if WKT is available. */
201 if (proj_wkt != NULL) {
203 }
204
205 return 0;
206}
207
208/*!
209 * \brief Compare projections including units
210 *
211 * \param proj_info1 projection info to compare
212 * \param proj_units1 projection units to compare
213 * \param proj_info2 projection info to compare
214 * \param proj_units2 projection units to compare
215
216 * \return -1 if not the same projection
217 * \return -2 if linear unit translation to meters fails
218 * \return -3 if not the same datum,
219 * \return -4 if not the same ellipsoid,
220 * \return -5 if UTM zone differs
221 * \return -6 if UTM hemisphere differs,
222 * \return -7 if false easting differs
223 * \return -8 if false northing differs,
224 * \return -9 if center longitude differs,
225 * \return -10 if center latitude differs,
226 * \return -11 if standard parallels differ,
227 * \return 1 if projections match.
228 */
230 const struct Key_Value *proj_units1,
231 const struct Key_Value *proj_info2,
232 const struct Key_Value *proj_units2)
233{
234 const char *proj1, *proj2;
235
236 if (proj_info1 == NULL && proj_info2 == NULL)
237 return TRUE;
238
239 /* -------------------------------------------------------------------- */
240 /* Are they both in the same projection? */
241 /* -------------------------------------------------------------------- */
242 /* prevent seg fault in G_find_key_value */
243 if (proj_info1 == NULL || proj_info2 == NULL)
244 return -1;
245
248
249 if (proj1 == NULL || proj2 == NULL || strcmp(proj1, proj2))
250 return -1;
251
252 /* -------------------------------------------------------------------- */
253 /* Verify that the linear unit translation to meters is OK. */
254 /* -------------------------------------------------------------------- */
255 /* prevent seg fault in G_find_key_value */
256 if (proj_units1 == NULL && proj_units2 == NULL)
257 return 1;
258
259 if (proj_units1 == NULL || proj_units2 == NULL)
260 return -2;
261
262 {
263 double a1 = 0, a2 = 0;
264
265 if (G_find_key_value("meters", proj_units1) != NULL)
266 a1 = atof(G_find_key_value("meters", proj_units1));
267 if (G_find_key_value("meters", proj_units2) != NULL)
268 a2 = atof(G_find_key_value("meters", proj_units2));
269
270 if (a1 && a2 && (fabs(a2 - a1) > 0.000001))
271 return -2;
272 }
273 /* compare unit name only if there is no to meter conversion factor */
274 if (G_find_key_value("meters", proj_units1) == NULL ||
275 G_find_key_value("meters", proj_units2) == NULL) {
276 const char *u_1 = NULL, *u_2 = NULL;
277
280
281 if ((u_1 && !u_2) || (!u_1 && u_2))
282 return -2;
283
284 /* the unit name can be arbitrary: the following can be the same
285 * us-ft (proj.4 keyword)
286 * U.S. Surveyor's Foot (proj.4 name)
287 * US survey foot (WKT)
288 * Foot_US (WKT)
289 */
290 if (u_1 && u_2 && G_strcasecmp(u_1, u_2))
291 return -2;
292 }
293
294 /* -------------------------------------------------------------------- */
295 /* Do they both have the same datum? */
296 /* -------------------------------------------------------------------- */
297 {
298 const char *d_1 = NULL, *d_2 = NULL;
299
300 d_1 = G_find_key_value("datum", proj_info1);
301 d_2 = G_find_key_value("datum", proj_info2);
302
303 if ((d_1 && !d_2) || (!d_1 && d_2))
304 return -3;
305
306 if (d_1 && d_2 && strcmp(d_1, d_2)) {
307 /* different datum short names can mean the same datum,
308 * see lib/gis/datum.table */
309 G_debug(1, "Different datum names");
310 }
311 }
312
313 /* -------------------------------------------------------------------- */
314 /* Do they both have the same ellipsoid? */
315 /* -------------------------------------------------------------------- */
316 {
317 const char *e_1 = NULL, *e_2 = NULL;
318
319 e_1 = G_find_key_value("ellps", proj_info1);
320 e_2 = G_find_key_value("ellps", proj_info2);
321
322 if (e_1 && e_2 && strcmp(e_1, e_2))
323 return -4;
324
325 if (e_1 == NULL || e_2 == NULL) {
326 double a1 = 0, a2 = 0;
327 double es1 = 0, es2 = 0;
328
329 /* it may happen that one proj_info has ellps,
330 * while the other has a, es: translate ellps to a, es */
331 if (e_1)
333 else {
334 if (G_find_key_value("a", proj_info1) != NULL)
335 a1 = atof(G_find_key_value("a", proj_info1));
336 if (G_find_key_value("es", proj_info1) != NULL)
338 }
339
340 if (e_2)
342 else {
343 if (G_find_key_value("a", proj_info2) != NULL)
344 a2 = atof(G_find_key_value("a", proj_info2));
345 if (G_find_key_value("es", proj_info2) != NULL)
347 }
348
349 /* it should be an error if a = 0 */
350 if ((a1 == 0 && a2 != 0) || (a1 != 0 && a2 == 0))
351 return -4;
352
353 if (a1 && a2 && (fabs(a2 - a1) > 0.000001))
354 return -4;
355
356 if ((es1 == 0 && es2 != 0) || (es1 != 0 && es2 == 0))
357 return -4;
358
359 if (es1 && es2 && (fabs(es2 - es1) > 0.000001))
360 return -4;
361 }
362 }
363
364 /* -------------------------------------------------------------------- */
365 /* Zone check specially for UTM */
366 /* -------------------------------------------------------------------- */
367 if (!strcmp(proj1, "utm") && !strcmp(proj2, "utm") &&
368 atof(G_find_key_value("zone", proj_info1)) !=
370 return -5;
371
372 /* -------------------------------------------------------------------- */
373 /* Hemisphere check specially for UTM */
374 /* -------------------------------------------------------------------- */
375 if (!strcmp(proj1, "utm") && !strcmp(proj2, "utm") &&
376 !!G_find_key_value("south", proj_info1) !=
377 !!G_find_key_value("south", proj_info2))
378 return -6;
379
380 /* -------------------------------------------------------------------- */
381 /* Do they both have the same false easting? */
382 /* -------------------------------------------------------------------- */
383
384 {
385 const char *x_0_1 = NULL, *x_0_2 = NULL;
386
389
390 if ((x_0_1 && !x_0_2) || (!x_0_1 && x_0_2))
391 return -7;
392
393 if (x_0_1 && x_0_2 && (fabs(atof(x_0_1) - atof(x_0_2)) > 0.000001))
394 return -7;
395 }
396
397 /* -------------------------------------------------------------------- */
398 /* Do they both have the same false northing? */
399 /* -------------------------------------------------------------------- */
400
401 {
402 const char *y_0_1 = NULL, *y_0_2 = NULL;
403
406
407 if ((y_0_1 && !y_0_2) || (!y_0_1 && y_0_2))
408 return -8;
409
410 if (y_0_1 && y_0_2 && (fabs(atof(y_0_1) - atof(y_0_2)) > 0.000001))
411 return -8;
412 }
413
414 /* -------------------------------------------------------------------- */
415 /* Do they have the same center longitude? */
416 /* -------------------------------------------------------------------- */
417
418 {
419 const char *l_1 = NULL, *l_2 = NULL;
420
421 l_1 = G_find_key_value("lon_0", proj_info1);
422 l_2 = G_find_key_value("lon_0", proj_info2);
423
424 if ((l_1 && !l_2) || (!l_1 && l_2))
425 return -9;
426
427 if (l_1 && l_2 && (fabs(atof(l_1) - atof(l_2)) > 0.000001))
428 return -9;
429
430 /* --------------------------------------------------------------------
431 */
432 /* Do they have the same center latitude? */
433 /* --------------------------------------------------------------------
434 */
435
436 l_1 = G_find_key_value("lat_0", proj_info1);
437 l_2 = G_find_key_value("lat_0", proj_info2);
438
439 if ((l_1 && !l_2) || (!l_1 && l_2))
440 return -10;
441
442 if (l_1 && l_2 && (fabs(atof(l_1) - atof(l_2)) > 0.000001))
443 return -10;
444
445 /* --------------------------------------------------------------------
446 */
447 /* Do they have the same standard parallels? */
448 /* --------------------------------------------------------------------
449 */
450
451 l_1 = G_find_key_value("lat_1", proj_info1);
452 l_2 = G_find_key_value("lat_1", proj_info2);
453
454 if ((l_1 && !l_2) || (!l_1 && l_2))
455 return -11;
456
457 if (l_1 && l_2 && (fabs(atof(l_1) - atof(l_2)) > 0.000001)) {
458 /* lat_1 differ */
459 /* check for swapped lat_1, lat_2 */
460 l_2 = G_find_key_value("lat_2", proj_info2);
461
462 if (!l_2)
463 return -11;
464 if (fabs(atof(l_1) - atof(l_2)) > 0.000001) {
465 return -11;
466 }
467 }
468
469 l_1 = G_find_key_value("lat_2", proj_info1);
470 l_2 = G_find_key_value("lat_2", proj_info2);
471
472 if ((l_1 && !l_2) || (!l_1 && l_2))
473 return -11;
474
475 if (l_1 && l_2 && (fabs(atof(l_1) - atof(l_2)) > 0.000001)) {
476 /* lat_2 differ */
477 /* check for swapped lat_1, lat_2 */
478 l_2 = G_find_key_value("lat_1", proj_info2);
479
480 if (!l_2)
481 return -11;
482 if (fabs(atof(l_1) - atof(l_2)) > 0.000001) {
483 return -11;
484 }
485 }
486 }
487
488 /* towgs84 ? */
489
490 /* -------------------------------------------------------------------- */
491 /* Add more details in later. */
492 /* -------------------------------------------------------------------- */
493
494 return 1;
495}
496
497/*!
498 \brief Write WKT definition to file
499
500 Any WKT string and version recognized by PROJ is supported.
501
502 \param location_name name of the location to write the WKT definition
503 \param wktstring pointer to WKT string
504
505 \return 0 success
506 \return -1 error writing
507 */
508int G_write_projwkt(const char *location_name, const char *wktstring)
509{
510 FILE *fp;
511 char path[GPATH_MAX];
512 int err, n;
513
514 if (!wktstring)
515 return 0;
516
518 snprintf(path, sizeof(path), "%s/%s/%s/%s", G_gisdbase(), location_name,
519 "PERMANENT", WKT_FILE);
520 else
521 G_file_name(path, "", WKT_FILE, "PERMANENT");
522
523 fp = fopen(path, "w");
524
525 if (!fp)
526 G_fatal_error(_("Unable to open output file <%s>: %s"), path,
527 strerror(errno));
528
529 err = 0;
530 n = strlen(wktstring);
531 if (wktstring[n - 1] != '\n') {
532 if (n != fprintf(fp, "%s\n", wktstring))
533 err = -1;
534 }
535 else {
536 if (n != fprintf(fp, "%s", wktstring))
537 err = -1;
538 }
539
540 if (fclose(fp) != 0)
541 G_fatal_error(_("Error closing output file <%s>: %s"), path,
542 strerror(errno));
543
544 return err;
545}
546
547/*!
548 \brief Write srid (spatial reference id) to file
549
550 A srid consists of an authority name and code and must be known to
551 PROJ.
552
553 \param location_name name of the location to write the srid
554 \param sridstring pointer to srid string
555
556 \return 0 success
557 \return -1 error writing
558 */
559int G_write_projsrid(const char *location_name, const char *sridstring)
560{
561 FILE *fp;
562 char path[GPATH_MAX];
563 int err, n;
564
565 if (!sridstring)
566 return 0;
567
569 snprintf(path, sizeof(path), "%s/%s/%s/%s", G_gisdbase(), location_name,
570 "PERMANENT", SRID_FILE);
571 else
572 G_file_name(path, "", SRID_FILE, "PERMANENT");
573
574 fp = fopen(path, "w");
575
576 if (!fp)
577 G_fatal_error(_("Unable to open output file <%s>: %s"), path,
578 strerror(errno));
579
580 err = 0;
581 n = strlen(sridstring);
582 if (sridstring[n - 1] != '\n') {
583 if (n != fprintf(fp, "%s\n", sridstring))
584 err = -1;
585 }
586 else {
587 if (n != fprintf(fp, "%s", sridstring))
588 err = -1;
589 }
590
591 if (fclose(fp) != 0)
592 G_fatal_error(_("Error closing output file <%s>: %s"), path,
593 strerror(errno));
594
595 return err;
596}
#define NULL
Definition ccmath.h:32
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
int G_legal_filename(const char *)
Check for legal database file name.
Definition legal_name.c:34
int G_get_ellipsoid_by_name(const char *, double *, double *)
Get ellipsoid parameters by name.
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition file_name.c:61
const char * G_gisdbase(void)
Get name of top level database directory.
Definition gisdbase.c:26
const char * G_find_key_value(const char *, const struct Key_Value *)
Find given key (case sensitive)
Definition key_value1.c:85
void G_write_key_value_file(const char *, const struct Key_Value *)
Write key/value pairs to file.
Definition key_value3.c:28
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition strings.c:47
int G_put_element_window(const struct Cell_head *, const char *, const char *)
Write the region.
Definition put_window.c:74
int G_mkdir(const char *)
Creates a new directory.
Definition paths.c:27
int G_debug(int, const char *,...) __attribute__((format(printf
void G_setenv_nogisrc(const char *, const char *)
Set environment name to value (doesn't update .gisrc)
Definition env.c:472
#define WKT_FILE
Definition gis.h:136
#define GPATH_MAX
Definition gis.h:199
#define SRID_FILE
Definition gis.h:137
#define TRUE
Definition gis.h:78
#define _(str)
Definition glocale.h:10
int G_make_location_crs(const char *location_name, struct Cell_head *wind, const struct Key_Value *proj_info, const struct Key_Value *proj_units, const char *proj_srid, const char *proj_wkt)
Create a new location.
Definition make_loc.c:183
int G_write_projsrid(const char *location_name, const char *sridstring)
Write srid (spatial reference id) to file.
Definition make_loc.c:559
int G_write_projwkt(const char *location_name, const char *wktstring)
Write WKT definition to file.
Definition make_loc.c:508
int G_compare_projections(const struct Key_Value *proj_info1, const struct Key_Value *proj_units1, const struct Key_Value *proj_info2, const struct Key_Value *proj_units2)
Compare projections including units.
Definition make_loc.c:229
int G_make_location(const char *location_name, struct Cell_head *wind, const struct Key_Value *proj_info, const struct Key_Value *proj_units)
Create a new location.
Definition make_loc.c:53
int G_make_location_epsg(const char *location_name, struct Cell_head *wind, const struct Key_Value *proj_info, const struct Key_Value *proj_units, const struct Key_Value *proj_epsg)
Create a new location.
Definition make_loc.c:127
2D/3D raster map header (used also for region)
Definition gis.h:446
Definition path.h:15
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)