15#include <grass/config.h>
22#include <grass/gprojects.h>
23#include <grass/glocale.h>
26#include "local_proto.h"
29#define CSVDIR "/etc/proj/ogr_csv"
31static void DatumNameMassage(
char **);
41struct gpj_units gpj_units[] = {
42 {
"km",
"1000.",
"Kilometer", 1000.0},
43 {
"m",
"1.",
"Meter", 1.0},
44 {
"dm",
"1/10",
"Decimeter", 0.1},
45 {
"cm",
"1/100",
"Centimeter", 0.01},
46 {
"mm",
"1/1000",
"Millimeter", 0.001},
47 {
"kmi",
"1852.0",
"International Nautical Mile", 1852.0},
48 {
"in",
"0.0254",
"International Inch", 0.0254},
49 {
"ft",
"0.3048",
"International Foot", 0.3048},
50 {
"yd",
"0.9144",
"International Yard", 0.9144},
51 {
"mi",
"1609.344",
"International Statute Mile", 1609.344},
52 {
"fath",
"1.8288",
"International Fathom", 1.8288},
53 {
"ch",
"20.1168",
"International Chain", 20.1168},
54 {
"link",
"0.201168",
"International Link", 0.201168},
55 {
"us-in",
"1./39.37",
"U.S. Surveyor's Inch", 0.0254},
56 {
"us-ft",
"0.304800609601219",
"U.S. Surveyor's Foot", 0.304800609601219},
57 {
"us-yd",
"0.914401828803658",
"U.S. Surveyor's Yard", 0.914401828803658},
58 {
"us-ch",
"20.11684023368047",
"U.S. Surveyor's Chain", 20.11684023368047},
59 {
"us-mi",
"1609.347218694437",
"U.S. Surveyor's Statute Mile",
61 {
"ind-yd",
"0.91439523",
"Indian Yard", 0.91439523},
62 {
"ind-ft",
"0.30479841",
"Indian Foot", 0.30479841},
63 {
"ind-ch",
"20.11669506",
"Indian Chain", 20.11669506},
66static char *grass_to_wkt(
const struct Key_Value *proj_info,
67 const struct Key_Value *proj_units,
68 const struct Key_Value *proj_epsg,
int esri_style,
71 OGRSpatialReferenceH hSRS;
72 char *wkt, *local_wkt;
83 OSRExportToPrettyWkt(hSRS, &wkt, 0);
85 OSRExportToWkt(hSRS, &wkt);
89 OSRDestroySpatialReference(hSRS);
113 const struct Key_Value *proj_units,
int esri_style,
116 return grass_to_wkt(proj_info, proj_units,
NULL, esri_style, prettify);
144 const struct Key_Value *proj_units,
145 const struct Key_Value *proj_epsg,
int esri_style,
148 return grass_to_wkt(proj_info, proj_units, proj_epsg, esri_style, prettify);
161 const struct Key_Value *proj_units)
163 struct pj_info pjinfo;
164 char *proj4, *proj4mod, *wkt, *modwkt, *startmod, *lastpart;
165 OGRSpatialReferenceH hSRS, hSRS2;
167 struct gpj_datum dstruct;
168 struct gpj_ellps estruct;
170 const char *ellpskv, *unit, *unfact;
171 char *ellps, *ellpslong, *datum, *params, *towgs84, *datumlongname, *start,
173 const char *sysname, *osrunit;
177 if ((proj_info ==
NULL) || (proj_units ==
NULL))
180 hSRS = OSRNewSpatialReference(
NULL);
183 if (
pj_get_kv(&pjinfo, proj_info, proj_units) < 0) {
184 G_warning(_(
"Unable parse GRASS PROJ_INFO file"));
190 if ((proj4 = pjinfo.def) ==
NULL) {
191 G_warning(_(
"Unable get PROJ.4-style parameter string"));
194 proj_destroy(pjinfo.pj);
198 if (unfact !=
NULL && (strcmp(pjinfo.proj,
"ll") != 0))
199 G_asprintf(&proj4mod,
"%s +to_meter=%s", proj4, unfact);
204 if ((errcode = OSRImportFromProj4(hSRS, proj4mod)) != OGRERR_NONE) {
205 G_warning(_(
"OGR can't parse PROJ.4-style parameter string: "
206 "%s (OGR Error code was %d)"),
218 if ((errcode = OSRExportToWkt(hSRS, &wkt)) != OGRERR_NONE) {
219 G_warning(_(
"OGR can't get WKT-style parameter string "
220 "(OGR Error code was %d)"),
235 datumlongname =
G_store(
"unknown");
240 datumlongname =
G_store(dstruct.longname);
242 ellps =
G_store(dstruct.ellps);
245 G_debug(3,
"GPJ_grass_to_osr: datum: <%s>", datum);
248 ellpslong =
G_store(estruct.longname);
249 DatumNameMassage(&ellpslong);
255 startmod = strstr(wkt,
"GEOGCS");
256 lastpart = strstr(wkt,
"PRIMEM");
257 len = strlen(wkt) - strlen(startmod);
259 if (haveparams == 2) {
262 char *paramkey, *paramvalue;
264 paramkey = strtok(params,
"=");
265 paramvalue = params + strlen(paramkey) + 1;
267 G_asprintf(&towgs84,
",TOWGS84[%s]", paramvalue);
275 sysname = OSRGetAttrValue(hSRS,
"PROJCS", 0);
276 if (sysname ==
NULL) {
282 if ((strcmp(sysname,
"unnamed") == 0) &&
289 osrunit = OSRGetAttrValue(hSRS,
"UNIT", 0);
295 double unfactf = atof(unfact);
299 startmod = strstr(lastpart, buff);
300 len = strlen(lastpart) - strlen(startmod);
301 lastpart[len] =
'\0';
306 G_asprintf(&end,
",UNIT[\"%s\",%.16g]]", unit, unfactf);
309 OSRDestroySpatialReference(hSRS);
312 "%sGEOGCS[\"%s\",DATUM[\"%s\",SPHEROID[\"%s\",%.16g,%.16g]%s],%s%s",
313 start, ellps, datumlongname, ellpslong, a, rf, towgs84, lastpart, end);
314 hSRS2 = OSRNewSpatialReference(modwkt);
348 const struct Key_Value *proj_units,
349 const struct Key_Value *proj_epsg)
357 epsgcode = atoi(epsgstr);
362 OGRSpatialReferenceH hSRS;
364 hSRS = OSRNewSpatialReference(
NULL);
366 OSRImportFromEPSG(hSRS, epsgcode);
373 double df[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
378 df[i] = atof(tokens[i]);
381 OSRSetTOWGS84(hSRS, df[0], df[1], df[2], df[3], df[4], df[5],
414 struct Key_Value **projunits, OGRSpatialReferenceH hSRS1,
417 struct Key_Value *temp_projinfo, *temp_projinfo_ext;
418 char *pszProj4 =
NULL, *pszRemaining;
419 char *pszProj =
NULL;
420 const char *pszProjCS =
NULL;
422 char *proj4_unit =
NULL;
423 struct gpj_datum dstruct;
425 OGRSpatialReferenceH hSRS;
426 int use_proj_extension;
441 OSRMorphFromESRI(hSRS);
444 use_proj_extension = 0;
447 ograttr = OSRGetAttrValue(hSRS,
"EXTENSION", 0);
448 if (ograttr && *ograttr && strcmp(ograttr,
"PROJ4") == 0) {
449 ograttr = OSRGetAttrValue(hSRS,
"EXTENSION", 1);
450 G_debug(3,
"proj4 extension:");
453 if (ograttr && *ograttr) {
455 OGRSpatialReferenceH hSRS2;
457 hSRS2 = OSRNewSpatialReference(
NULL);
461 if (OSRImportFromProj4(hSRS2, proj4ext) != OGRERR_NONE) {
462 G_warning(_(
"Updating spatial reference with embedded proj4 "
463 "definition failed. "
464 "Proj4 definition: <%s>"),
466 OSRDestroySpatialReference(hSRS2);
473 G_warning(_(
"Updating spatial reference with embedded proj4 "
481 pszProjCS = OSRGetAttrValue(hSRS,
"PROJCS", 0);
483 pszProjCS = OSRGetAttrValue(hSRS,
"GEOGCS", 0);
495 snprintf(
path,
sizeof(
path),
"%s/etc/proj/projections",
506 use_proj_extension = 1;
515 if (!OSRIsGeographic(hSRS) && !OSRIsProjected(hSRS))
521 if (OSRIsGeographic(hSRS)) {
522 cellhd->proj = PROJECTION_LL;
525 else if (OSRGetUTMZone(hSRS, &bNorth) != 0) {
526 cellhd->proj = PROJECTION_UTM;
527 cellhd->zone = OSRGetUTMZone(hSRS, &bNorth);
532 cellhd->proj = PROJECTION_OTHER;
540 if (OSRExportToProj4(hSRS, &pszProj4) != OGRERR_NONE)
552 pszRemaining =
G_store(pszProj4);
554 pszProj4 = pszRemaining;
555 while ((pszRemaining = strstr(pszRemaining,
"+")) !=
NULL) {
556 char *pszToken, *pszValue;
561 pszToken = pszRemaining;
562 while (*pszRemaining !=
' ' && *pszRemaining !=
'\0')
565 if (*pszRemaining ==
' ') {
566 *pszRemaining =
'\0';
571 if (strstr(pszToken,
"=") !=
NULL) {
572 pszValue = strstr(pszToken,
"=");
577 pszValue =
"defined";
604 proj4_unit =
G_store(pszValue);
611 G_warning(_(
"No projection name! Projection parameters likely to be "
618 pszProjCS = OSRGetAttrValue(hSRS,
"PROJCS", 0);
620 pszProjCS = OSRGetAttrValue(hSRS,
"GEOGCS", 0);
631 snprintf(
path,
sizeof(
path),
"%s/etc/proj/projections",
647 const char *pszDatumNameConst;
648 struct datum_list *
list, *listhead;
649 char *dum1, *dum2, *pszDatumName;
652 if (!use_proj_extension)
653 pszDatumNameConst = OSRGetAttrValue(hSRS,
"DATUM", 0);
657 if (pszDatumNameConst) {
661 pszDatumName =
G_store(pszDatumNameConst);
662 DatumNameMassage(&pszDatumName);
663 G_debug(3,
"GPJ_osr_to_grass: pszDatumNameConst: <%s>",
678 if (paramspresent < 2)
681 "Datum <%s> not recognised by GRASS and no "
688 if (paramspresent < 2) {
692 char *params, *chosenparams =
NULL;
700 "Datum <%s> apparently recognised by GRASS but "
701 "no parameters found. "
702 "You may want to look into this.",
704 else if (datumtrans > paramsets) {
708 "Invalid transformation number %d; valid range is "
710 "Leaving datum transform parameters unspecified.",
711 datumtrans, paramsets);
716 struct gpj_datum_transform_list *tlist, *old;
722 if (tlist->count == datumtrans)
723 chosenparams =
G_store(tlist->params);
727 }
while (tlist !=
NULL);
731 if (chosenparams !=
NULL) {
732 char *paramkey, *paramvalue;
734 paramkey = strtok(chosenparams,
"=");
735 paramvalue = chosenparams + strlen(paramkey) + 1;
759 else if (!use_proj_extension) {
762 const char *pszSemiMajor = OSRGetAttrValue(hSRS,
"SPHEROID", 1);
763 const char *pszInvFlat = OSRGetAttrValue(hSRS,
"SPHEROID", 2);
765 if (pszSemiMajor !=
NULL && pszInvFlat !=
NULL) {
767 struct ellps_list *
list, *listhead;
768 double a = atof(pszSemiMajor), invflat = atof(pszInvFlat), flat;
778 es = flat * (2.0 - flat);
787 if ((a ==
list->a || fabs(a -
list->a) < 0.1 ||
788 fabs(1 - a /
list->a) < 0.0000001) &&
789 ((es == 0 &&
list->es == 0) ||
791 (invflat ==
list->rf ||
792 fabs(invflat -
list->rf) < 0.0000001))) {
798 if (listhead !=
NULL)
808 snprintf(es_str,
sizeof(es_str),
"%.16g", es);
818 else if (use_proj_extension) {
824 snprintf(parmstr,
sizeof(parmstr),
"%.16g", a);
826 snprintf(parmstr,
sizeof(parmstr),
"%.16g", es);
838 for (i = 0; i < temp_projinfo->nitems; i++)
853 if (OSRIsGeographic(hSRS)) {
860 char szFormatBuf[256];
861 char *pszUnitsName =
NULL;
863 char *pszUnitsPlural, *pszStringEnd;
865 dfToMeters = OSRGetLinearUnits(hSRS, &pszUnitsName);
875 if ((
G_strcasecmp(pszUnitsName,
"unknown") == 0) && (dfToMeters == 1.))
883 if (dfToMeters != 1. && proj4_unit) {
887 while (gpj_units[i].
id !=
NULL) {
888 if (strcmp(proj4_unit, gpj_units[i].
id) == 0) {
900 pszUnitsPlural = G_malloc(strlen(pszUnitsName) + 3);
901 strcpy(pszUnitsPlural, pszUnitsName);
902 pszStringEnd = pszUnitsPlural + strlen(pszUnitsPlural) - 4;
905 pszStringEnd[1] =
'e';
906 pszStringEnd[2] =
'e';
910 pszStringEnd[4] =
'e';
911 pszStringEnd[5] =
's';
912 pszStringEnd[6] =
'\0';
916 pszStringEnd[4] =
's';
917 pszStringEnd[5] =
'\0';
923 snprintf(szFormatBuf,
sizeof(szFormatBuf),
"%.16g", dfToMeters);
928 OSRDestroySpatialReference(hSRS);
936 if (cellhd !=
NULL) {
937 cellhd->proj = PROJECTION_XY;
946 if (hSRS !=
NULL && hSRS != hSRS1)
947 OSRDestroySpatialReference(hSRS);
972 struct Key_Value **projunits,
const char *wkt,
981 OGRSpatialReferenceH hSRS;
986 hSRS = OSRNewSpatialReference(wkt);
989 OSRDestroySpatialReference(hSRS);
1001 static char *buf =
NULL;
1034static const char *papszDatumEquiv[] = {
1035 "Militar_Geographische_Institute",
1036 "Militar_Geographische_Institut",
1037 "World_Geodetic_System_1984",
1039 "World_Geodetic_System_1972",
1041 "European_Terrestrial_Reference_System_89",
1042 "European_Terrestrial_Reference_System_1989",
1043 "European_Reference_System_1989",
1044 "European_Terrestrial_Reference_System_1989",
1046 "European_Terrestrial_Reference_System_1989",
1048 "European_Terrestrial_Reference_System_1989",
1050 "European_Terrestrial_Reference_System_1989",
1052 "New_Zealand_Geodetic_Datum_2000",
1057 "Campo_Inchauspe_1969",
1060 "System_Jednotne_Trigonometricke_Site_Katastralni",
1062 "Militar_Geographische_Institut",
1064 "Deutsches_Hauptdreiecksnetz",
1065 "Rauenberg_Datum_83",
1066 "Deutsches_Hauptdreiecksnetz",
1067 "South_American_1969",
1068 "South_American_Datum_1969",
1069 "International_Terrestrial_Reference_Frame_1992",
1083static void DatumNameMassage(
char **ppszDatum)
1086 char *pszDatum = *ppszDatum;
1088 G_debug(3,
"DatumNameMassage: Raw string found <%s>", (
char *)pszDatum);
1092 for (i = 0; pszDatum[i] !=
'\0'; i++) {
1093 if (!(pszDatum[i] >=
'A' && pszDatum[i] <=
'Z') &&
1094 !(pszDatum[i] >=
'a' && pszDatum[i] <=
'z') &&
1095 !(pszDatum[i] >=
'0' && pszDatum[i] <=
'9')) {
1103 for (i = 1, j = 0; pszDatum[i] !=
'\0'; i++) {
1104 if (pszDatum[j] ==
'_' && pszDatum[i] ==
'_')
1107 pszDatum[++j] = pszDatum[i];
1109 if (pszDatum[j] ==
'_')
1112 pszDatum[j + 1] =
'\0';
1118 G_debug(3,
"DatumNameMassage: Search for datum equivalences of <%s>",
1120 for (i = 0; papszDatumEquiv[i] !=
NULL; i += 2) {
1121 if (
EQUAL(*ppszDatum, papszDatumEquiv[i])) {
1123 *ppszDatum =
G_store(papszDatumEquiv[i + 1]);
void G_free(void *buf)
Free allocated memory.
int G_asprintf(char **out, const char *fmt,...)
char * GPJ_grass_to_wkt(const struct Key_Value *proj_info, const struct Key_Value *proj_units, int esri_style, int prettify)
Converts a GRASS co-ordinate system representation to WKT style.
OGRSpatialReferenceH GPJ_grass_to_osr2(const struct Key_Value *proj_info, const struct Key_Value *proj_units, const struct Key_Value *proj_epsg)
Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object. EPSG code is preferred if avai...
int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, struct Key_Value **projunits, OGRSpatialReferenceH hSRS1, int datumtrans)
Converts an OGRSpatialReferenceH object to a GRASS co-ordinate system.
int GPJ_wkt_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo, struct Key_Value **projunits, const char *wkt, int datumtrans)
Converts a WKT projection description to a GRASS co-ordinate system.
char * GPJ_grass_to_wkt2(const struct Key_Value *proj_info, const struct Key_Value *proj_units, const struct Key_Value *proj_epsg, int esri_style, int prettify)
Converts a GRASS co-ordinate system representation to WKT style. EPSG code is preferred if available.
OGRSpatialReferenceH GPJ_grass_to_osr(const struct Key_Value *proj_info, const struct Key_Value *proj_units)
Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object.
const char * GPJ_set_csv_loc(const char *name)
int G_debug(int level, const char *msg,...)
Print debugging message.
int GPJ_get_ellipsoid_by_name(const char *name, struct gpj_ellps *estruct)
Looks up ellipsoid in ellipsoid table and returns the a, e2 parameters for the ellipsoid.
struct ellps_list * read_ellipsoid_table(int fatal)
int GPJ__get_ellipsoid_params(const struct Key_Value *proj_keys, double *a, double *e2, double *rf)
Get the ellipsoid parameters from proj keys structure.
void free_ellps_list(struct ellps_list *elist)
void GPJ_free_ellps(struct gpj_ellps *estruct)
Free ellipsoid data structure.
int pj_get_kv(struct pj_info *info, const struct Key_Value *in_proj_keys, const struct Key_Value *in_units_keys)
Create a pj_info struct Co-ordinate System definition from a set of PROJ_INFO / PROJ_UNITS-style key-...
void G_warning(const char *msg,...)
Print a warning message to stderr.
const char * G_gisbase(void)
Get full path name of the top level module directory.
void G_free_key_value(struct Key_Value *kv)
Free allocated Key_Value structure.
void G_set_key_value(const char *key, const char *value, struct Key_Value *kv)
Set value for given key.
const char * G_find_key_value(const char *key, const struct Key_Value *kv)
Find given key (case sensitive).
struct Key_Value * G_create_key_value(void)
Allocate and initialize Key_Value structure.
int G_lookup_key_value_from_file(const char *file, const char *key, char value[], int n)
Look up for key in file.
int GPJ_get_default_datum_params_by_name(const char *name, char **params)
"Last resort" function to retrieve a "default" set of datum parameters for a datum (N....
void GPJ_free_datum_transform(struct gpj_datum_transform_list *item)
Free the memory used by a gpj_datum_transform_list struct.
void GPJ_free_datum(struct gpj_datum *dstruct)
Free the memory used for the strings in a gpj_datum struct.
struct gpj_datum_transform_list * GPJ_get_datum_transform_by_name(const char *inputname)
Internal function to find all possible sets of transformation parameters for a particular datum.
void free_datum_list(struct datum_list *dstruct)
Free the memory used by a datum_list linked list structure.
int GPJ__get_datum_params(const struct Key_Value *projinfo, char **datumname, char **params)
Extract the datum transformation-related parameters from a set of general PROJ_INFO parameters.
int GPJ_get_datum_by_name(const char *name, struct gpj_datum *dstruct)
Look up a string in datum.table file to see if it is a valid datum name and if so place its informati...
struct datum_list * read_datum_table(void)
Read the current GRASS datum.table from disk and store in memory.
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower).
char * G_store(const char *s)
Copy string to allocated memory.
void G_free_tokens(char **tokens)
Free memory allocated to tokens.
char ** G_tokenize(const char *buf, const char *delim)
Tokenize string.
int G_number_of_tokens(char **tokens)
Return number of tokens.