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