123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107 |
- /*!
- \file lib/proj/convert.c
- \brief GProj Library - Functions for manipulating co-ordinate
- system representations
- (C) 2003-2018 by the GRASS Development Team
-
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- \author Paul Kelly, Frank Warmerdam, Markus Metz
- */
- #include <grass/config.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/gprojects.h>
- #include <grass/glocale.h>
- #ifdef HAVE_OGR
- #include <cpl_csv.h>
- #include "local_proto.h"
- /* GRASS relative location of OGR co-ordinate system lookup tables */
- #define CSVDIR "/etc/proj/ogr_csv"
- static void DatumNameMassage(char **);
- #endif
- /* from proj-5.0.0/src/pj_units.c */
- struct gpj_units {
- char *id; /* units keyword */
- char *to_meter; /* multiply by value to get meters */
- char *name; /* comments */
- double factor; /* to_meter factor in actual numbers */
- };
- struct gpj_units
- gpj_units[] = {
- {"km", "1000.", "Kilometer", 1000.0},
- {"m", "1.", "Meter", 1.0},
- {"dm", "1/10", "Decimeter", 0.1},
- {"cm", "1/100", "Centimeter", 0.01},
- {"mm", "1/1000", "Millimeter", 0.001},
- {"kmi", "1852.0", "International Nautical Mile", 1852.0},
- {"in", "0.0254", "International Inch", 0.0254},
- {"ft", "0.3048", "International Foot", 0.3048},
- {"yd", "0.9144", "International Yard", 0.9144},
- {"mi", "1609.344", "International Statute Mile", 1609.344},
- {"fath", "1.8288", "International Fathom", 1.8288},
- {"ch", "20.1168", "International Chain", 20.1168},
- {"link", "0.201168", "International Link", 0.201168},
- {"us-in", "1./39.37", "U.S. Surveyor's Inch", 0.0254},
- {"us-ft", "0.304800609601219", "U.S. Surveyor's Foot", 0.304800609601219},
- {"us-yd", "0.914401828803658", "U.S. Surveyor's Yard", 0.914401828803658},
- {"us-ch", "20.11684023368047", "U.S. Surveyor's Chain", 20.11684023368047},
- {"us-mi", "1609.347218694437", "U.S. Surveyor's Statute Mile", 1609.347218694437},
- {"ind-yd", "0.91439523", "Indian Yard", 0.91439523},
- {"ind-ft", "0.30479841", "Indian Foot", 0.30479841},
- {"ind-ch", "20.11669506", "Indian Chain", 20.11669506},
- {NULL, NULL, NULL, 0.0}
- };
- static char *grass_to_wkt(const struct Key_Value *proj_info,
- const struct Key_Value *proj_units,
- const struct Key_Value *proj_epsg,
- int esri_style, int prettify)
- {
- #ifdef HAVE_OGR
- OGRSpatialReferenceH hSRS;
- char *wkt, *local_wkt;
- hSRS = GPJ_grass_to_osr2(proj_info, proj_units, proj_epsg);
- if (hSRS == NULL)
- return NULL;
- if (esri_style)
- OSRMorphToESRI(hSRS);
- if (prettify)
- OSRExportToPrettyWkt(hSRS, &wkt, 0);
- else
- OSRExportToWkt(hSRS, &wkt);
- local_wkt = G_store(wkt);
- CPLFree(wkt);
- OSRDestroySpatialReference(hSRS);
- return local_wkt;
- #else
- G_warning(_("GRASS is not compiled with OGR support"));
- return NULL;
- #endif
- }
- /*!
- * \brief Converts a GRASS co-ordinate system representation to WKT style.
- *
- * Takes a GRASS co-ordinate system as specified by two sets of
- * key/value pairs derived from the PROJ_INFO and PROJ_UNITS files,
- * and converts it to the 'Well Known Text' format.
- *
- * \param proj_info Set of GRASS PROJ_INFO key/value pairs
- * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
- * \param esri_style boolean Output ESRI-style WKT (Use OSRMorphToESRI()
- * function provided by OGR library)
- * \param prettify boolean Use linebreaks and indents to 'prettify' output
- * WKT string (Use OSRExportToPrettyWkt() function in OGR)
- *
- * \return Pointer to a string containing the co-ordinate system in
- * WKT format
- * \return NULL on error
- */
- char *GPJ_grass_to_wkt(const struct Key_Value *proj_info,
- const struct Key_Value *proj_units,
- int esri_style, int prettify)
- {
- return grass_to_wkt(proj_info, proj_units, NULL, esri_style, prettify);
- }
- /*!
- * \brief Converts a GRASS co-ordinate system representation to WKT
- * style. EPSG code is preferred if available.
- *
- * Takes a GRASS co-ordinate system as specified key/value pairs
- * derived from the PROJ_EPSG file. TOWGS84 parameter is scanned
- * from PROJ_INFO file and appended to co-ordinate system definition
- * imported from EPSG code by GDAL library. PROJ_UNITS file is
- * ignored. The function converts it to the 'Well Known Text' format.
- *
- * \todo Merge with GPJ_grass_to_wkt() in GRASS 8.
- *
- * \param proj_info Set of GRASS PROJ_INFO key/value pairs
- * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
- * \param proj_epsg Set of GRASS PROJ_EPSG key/value pairs
- * \param esri_style boolean Output ESRI-style WKT (Use OSRMorphToESRI()
- * function provided by OGR library)
- * \param prettify boolean Use linebreaks and indents to 'prettify' output
- * WKT string (Use OSRExportToPrettyWkt() function in OGR)
- *
- * \return Pointer to a string containing the co-ordinate system in
- * WKT format
- * \return NULL on error
- */
- 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)
- {
- return grass_to_wkt(proj_info, proj_units, proj_epsg, esri_style, prettify);
- }
- #ifdef HAVE_OGR
- /*!
- * \brief Converts a GRASS co-ordinate system to an OGRSpatialReferenceH object.
- *
- * \param proj_info Set of GRASS PROJ_INFO key/value pairs
- * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
- *
- * \return OGRSpatialReferenceH object representing the co-ordinate system
- * defined by proj_info and proj_units or NULL if it fails
- */
- OGRSpatialReferenceH GPJ_grass_to_osr(const struct Key_Value * proj_info,
- const struct Key_Value * proj_units)
- {
- struct pj_info pjinfo;
- char *proj4, *proj4mod, *wkt, *modwkt, *startmod, *lastpart;
- OGRSpatialReferenceH hSRS, hSRS2;
- OGRErr errcode;
- struct gpj_datum dstruct;
- struct gpj_ellps estruct;
- size_t len;
- const char *ellpskv, *unit, *unfact;
- char *ellps, *ellpslong, *datum, *params, *towgs84, *datumlongname,
- *start, *end;
- const char *sysname, *osrunit, *osrunfact;
- double a, es, rf;
- int haveparams = 0;
- if ((proj_info == NULL) || (proj_units == NULL))
- return NULL;
- hSRS = OSRNewSpatialReference(NULL);
- /* create PROJ structure from GRASS key/value pairs */
- if (pj_get_kv(&pjinfo, proj_info, proj_units) < 0) {
- G_warning(_("Unable parse GRASS PROJ_INFO file"));
- return NULL;
- }
- /* fetch the PROJ definition */
- /* TODO: get the PROJ definition as used by pj_get_kv() */
- if ((proj4 = pjinfo.def) == NULL) {
- G_warning(_("Unable get PROJ.4-style parameter string"));
- return NULL;
- }
- #ifdef HAVE_PROJ_H
- proj_destroy(pjinfo.pj);
- #else
- pj_free(pjinfo.pj);
- #endif
- unit = G_find_key_value("unit", proj_units);
- unfact = G_find_key_value("meters", proj_units);
- if (unfact != NULL && (strcmp(pjinfo.proj, "ll") != 0))
- G_asprintf(&proj4mod, "%s +to_meter=%s", proj4, unfact);
- else
- proj4mod = G_store(proj4);
- /* create GDAL OSR from proj string */
- if ((errcode = OSRImportFromProj4(hSRS, proj4mod)) != OGRERR_NONE) {
- G_warning(_("OGR can't parse PROJ.4-style parameter string: "
- "%s (OGR Error code was %d)"), proj4mod, errcode);
- return NULL;
- }
- G_free(proj4mod);
- /* this messes up PROJCS versus GEOGCS!
- sysname = G_find_key_value("name", proj_info);
- if (sysname)
- OSRSetProjCS(hSRS, sysname);
- */
- if ((errcode = OSRExportToWkt(hSRS, &wkt)) != OGRERR_NONE) {
- G_warning(_("OGR can't get WKT-style parameter string "
- "(OGR Error code was %d)"), errcode);
- return NULL;
- }
- ellpskv = G_find_key_value("ellps", proj_info);
- GPJ__get_ellipsoid_params(proj_info, &a, &es, &rf);
- haveparams = GPJ__get_datum_params(proj_info, &datum, ¶ms);
- if (ellpskv != NULL)
- ellps = G_store(ellpskv);
- else
- ellps = NULL;
- if ((datum == NULL) || (GPJ_get_datum_by_name(datum, &dstruct) < 0)) {
- datumlongname = G_store("unknown");
- if (ellps == NULL)
- ellps = G_store("unnamed");
- }
- else {
- datumlongname = G_store(dstruct.longname);
- if (ellps == NULL)
- ellps = G_store(dstruct.ellps);
- GPJ_free_datum(&dstruct);
- }
- G_debug(3, "GPJ_grass_to_osr: datum: <%s>", datum);
- G_free(datum);
- if (GPJ_get_ellipsoid_by_name(ellps, &estruct) > 0) {
- ellpslong = G_store(estruct.longname);
- DatumNameMassage(&ellpslong);
- GPJ_free_ellps(&estruct);
- }
- else
- ellpslong = G_store(ellps);
- startmod = strstr(wkt, "GEOGCS");
- lastpart = strstr(wkt, "PRIMEM");
- len = strlen(wkt) - strlen(startmod);
- wkt[len] = '\0';
- if (haveparams == 2) {
- /* Only put datum params into the WKT if they were specifically
- * specified in PROJ_INFO */
- char *paramkey, *paramvalue;
- paramkey = strtok(params, "=");
- paramvalue = params + strlen(paramkey) + 1;
- if (G_strcasecmp(paramkey, "towgs84") == 0)
- G_asprintf(&towgs84, ",TOWGS84[%s]", paramvalue);
- else
- towgs84 = G_store("");
- G_free(params);
- }
- else
- towgs84 = G_store("");
- sysname = OSRGetAttrValue(hSRS, "PROJCS", 0);
- if (sysname == NULL) {
- /* Not a projected co-ordinate system */
- start = G_store("");
- end = G_store("");
- }
- else {
- if ((strcmp(sysname, "unnamed") == 0) &&
- (G_find_key_value("name", proj_info) != NULL))
- G_asprintf(&start, "PROJCS[\"%s\",",
- G_find_key_value("name", proj_info));
- else
- start = G_store(wkt);
- osrunit = OSRGetAttrValue(hSRS, "UNIT", 0);
- osrunfact = OSRGetAttrValue(hSRS, "UNIT", 1);
- if ((unfact == NULL) || (G_strcasecmp(osrunit, "unknown") != 0))
- end = G_store("");
- else {
- char *buff;
- double unfactf = atof(unfact);
- G_asprintf(&buff, ",UNIT[\"%s\",", osrunit);
- startmod = strstr(lastpart, buff);
- len = strlen(lastpart) - strlen(startmod);
- lastpart[len] = '\0';
- G_free(buff);
- if (unit == NULL)
- unit = "unknown";
- G_asprintf(&end, ",UNIT[\"%s\",%.16g]]", unit, unfactf);
- }
- }
- OSRDestroySpatialReference(hSRS);
- G_asprintf(&modwkt,
- "%sGEOGCS[\"%s\",DATUM[\"%s\",SPHEROID[\"%s\",%.16g,%.16g]%s],%s%s",
- start, ellps, datumlongname, ellpslong, a, rf, towgs84,
- lastpart, end);
- hSRS2 = OSRNewSpatialReference(modwkt);
- G_free(modwkt);
- CPLFree(wkt);
- G_free(start);
- G_free(ellps);
- G_free(datumlongname);
- G_free(ellpslong);
- G_free(towgs84);
- G_free(end);
- return hSRS2;
- }
- /*!
- * \brief Converts a GRASS co-ordinate system to an
- * OGRSpatialReferenceH object. EPSG code is preferred if available.
- *
- * The co-ordinate system definition is imported from EPSG (by GDAL)
- * definition if available. TOWGS84 parameter is scanned from
- * PROJ_INFO file and appended to co-ordinate system definition. If
- * EPSG code is not available, PROJ_INFO file is used as
- * GPJ_grass_to_osr() does.
- * \todo Merge with GPJ_grass_to_osr() in GRASS 8.
- *
- * \param proj_info Set of GRASS PROJ_INFO key/value pairs
- * \param proj_units Set of GRASS PROJ_UNIT key/value pairs
- * \param proj_epsg Set of GRASS PROJ_EPSG key/value pairs
- *
- * \return OGRSpatialReferenceH object representing the co-ordinate system
- * defined by proj_info and proj_units or NULL if it fails
- */
- OGRSpatialReferenceH GPJ_grass_to_osr2(const struct Key_Value * proj_info,
- const struct Key_Value * proj_units,
- const struct Key_Value * proj_epsg)
- {
- int epsgcode = 0;
-
- if (proj_epsg) {
- const char *epsgstr = G_find_key_value("epsg", proj_epsg);
- if (epsgstr)
- epsgcode = atoi(epsgstr);
- }
- if (epsgcode) {
- const char *towgs84;
- OGRSpatialReferenceH hSRS;
-
- hSRS = OSRNewSpatialReference(NULL);
- OSRImportFromEPSG(hSRS, epsgcode);
- /* take +towgs84 from projinfo file if defined */
- towgs84 = G_find_key_value("towgs84", proj_info);
- if (towgs84) {
- char **tokens;
- int i;
- double df[] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
-
- tokens = G_tokenize(towgs84, ",");
- for (i = 0; i < G_number_of_tokens(tokens); i++)
- df[i] = atof(tokens[i]);
- G_free_tokens(tokens);
-
- OSRSetTOWGS84(hSRS, df[0], df[1], df[2], df[3], df[4], df[5], df[6]);
- }
-
- return hSRS;
- }
- return GPJ_grass_to_osr(proj_info, proj_units);
- }
- /*!
- * \brief Converts an OGRSpatialReferenceH object to a GRASS co-ordinate system.
- *
- * \param cellhd Pointer to a GRASS Cell_head structure that will have its
- * projection-related members populated with appropriate values
- * \param projinfo Pointer to a pointer which will have a GRASS Key_Value
- * structure allocated containing a set of GRASS PROJ_INFO values
- * \param projunits Pointer to a pointer which will have a GRASS Key_Value
- * structure allocated containing a set of GRASS PROJ_UNITS values
- * \param hSRS OGRSpatialReferenceH object containing the co-ordinate
- * system to be converted
- * \param datumtrans Index number of datum parameter set to use, 0 to leave
- * unspecified
- *
- * \return 2 if a projected or lat/long co-ordinate system has been
- * defined
- * \return 1 if an unreferenced XY co-ordinate system has
- * been defined
- */
- int GPJ_osr_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo,
- struct Key_Value **projunits, OGRSpatialReferenceH hSRS1,
- int datumtrans)
- {
- struct Key_Value *temp_projinfo;
- char *pszProj4 = NULL, *pszRemaining;
- char *pszProj = NULL;
- const char *pszProjCS = NULL;
- char *datum = NULL;
- char *proj4_unit = NULL;
- struct gpj_datum dstruct;
- const char *ograttr;
- OGRSpatialReferenceH hSRS;
- *projinfo = NULL;
- *projunits = NULL;
- hSRS = hSRS1;
- if (hSRS == NULL)
- goto default_to_xy;
- /* Set finder function for locating OGR csv co-ordinate system tables */
- /* SetCSVFilenameHook(GPJ_set_csv_loc); */
- /* Hopefully this doesn't do any harm if it wasn't in ESRI format
- * to start with... */
- OSRMorphFromESRI(hSRS);
- *projinfo = G_create_key_value();
- /* use proj4 definition from EXTENSION attribute if existing */
- ograttr = OSRGetAttrValue(hSRS, "EXTENSION", 0);
- if (ograttr && *ograttr && strcmp(ograttr, "PROJ4") == 0) {
- ograttr = OSRGetAttrValue(hSRS, "EXTENSION", 1);
- G_debug(3, "proj4 extension:");
- G_debug(3, "%s", ograttr);
-
- if (ograttr && *ograttr) {
- char *proj4ext;
- OGRSpatialReferenceH hSRS2;
- hSRS2 = OSRNewSpatialReference(NULL);
- proj4ext = G_store(ograttr);
- /* test */
- if (OSRImportFromProj4(hSRS2, proj4ext) != OGRERR_NONE) {
- G_warning(_("Updating spatial reference with embedded proj4 definition failed. "
- "Proj4 definition: <%s>"), proj4ext);
- OSRDestroySpatialReference(hSRS2);
- }
- else {
- /* use new OGR spatial reference defined with embedded proj4 string */
- /* TODO: replace warning with important_message once confirmed working */
- G_warning(_("Updating spatial reference with embedded proj4 definition"));
- /* -------------------------------------------------------------------- */
- /* Derive the user name for the coordinate system. */
- /* -------------------------------------------------------------------- */
- pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0);
- if (!pszProjCS)
- pszProjCS = OSRGetAttrValue(hSRS, "GEOGCS", 0);
- if (pszProjCS) {
- G_set_key_value("name", pszProjCS, *projinfo);
- }
- else if (pszProj) {
- char path[4095];
- char name[80];
-
- /* use name of the projection as name for the coordinate system */
- sprintf(path, "%s/etc/proj/projections", G_gisbase());
- if (G_lookup_key_value_from_file(path, pszProj, name, sizeof(name)) >
- 0)
- G_set_key_value("name", name, *projinfo);
- else
- G_set_key_value("name", pszProj, *projinfo);
- }
- /* the original hSRS1 is left as is, ok? */
- hSRS = hSRS2;
- }
- G_free(proj4ext);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Set cellhd for well known coordinate systems. */
- /* -------------------------------------------------------------------- */
- if (!OSRIsGeographic(hSRS) && !OSRIsProjected(hSRS))
- goto default_to_xy;
- if (cellhd) {
- int bNorth;
- if (OSRIsGeographic(hSRS)) {
- cellhd->proj = PROJECTION_LL;
- cellhd->zone = 0;
- }
- else if (OSRGetUTMZone(hSRS, &bNorth) != 0) {
- cellhd->proj = PROJECTION_UTM;
- cellhd->zone = OSRGetUTMZone(hSRS, &bNorth);
- if (!bNorth)
- cellhd->zone *= -1;
- }
- else {
- cellhd->proj = PROJECTION_OTHER;
- cellhd->zone = 0;
- }
- }
- /* -------------------------------------------------------------------- */
- /* Get the coordinate system definition in PROJ.4 format. */
- /* -------------------------------------------------------------------- */
- if (OSRExportToProj4(hSRS, &pszProj4) != OGRERR_NONE)
- goto default_to_xy;
- /* -------------------------------------------------------------------- */
- /* Parse the PROJ.4 string into key/value pairs. Do a bit of */
- /* extra work to "GRASSify" the result. */
- /* -------------------------------------------------------------------- */
- temp_projinfo = G_create_key_value();
- /* Create "local" copy of proj4 string so we can modify and free it
- * using GRASS functions */
- pszRemaining = G_store(pszProj4);
- CPLFree(pszProj4);
- pszProj4 = pszRemaining;
- while ((pszRemaining = strstr(pszRemaining, "+")) != NULL) {
- char *pszToken, *pszValue;
- pszRemaining++;
- /* Advance pszRemaining to end of this token[=value] pair */
- pszToken = pszRemaining;
- while (*pszRemaining != ' ' && *pszRemaining != '\0')
- pszRemaining++;
- if (*pszRemaining == ' ') {
- *pszRemaining = '\0';
- pszRemaining++;
- }
- /* parse token, and value */
- if (strstr(pszToken, "=") != NULL) {
- pszValue = strstr(pszToken, "=");
- *pszValue = '\0';
- pszValue++;
- }
- else
- pszValue = "defined";
- /* projection name */
- if (G_strcasecmp(pszToken, "proj") == 0) {
- /* The ll projection is known as longlat in PROJ.4 */
- if (G_strcasecmp(pszValue, "longlat") == 0)
- pszValue = "ll";
- pszProj = pszValue;
- }
- /* discard @null nadgrids */
- if (G_strcasecmp(pszToken, "nadgrids") == 0 &&
- G_strcasecmp(pszValue, "@null") == 0)
- continue;
- /* Ellipsoid and datum handled separately below */
- if (G_strcasecmp(pszToken, "ellps") == 0
- || G_strcasecmp(pszToken, "a") == 0
- || G_strcasecmp(pszToken, "b") == 0
- || G_strcasecmp(pszToken, "es") == 0
- || G_strcasecmp(pszToken, "rf") == 0
- || G_strcasecmp(pszToken, "datum") == 0)
- continue;
- /* We will handle units separately */
- if (G_strcasecmp(pszToken, "to_meter") == 0)
- continue;
- if (G_strcasecmp(pszToken, "units") == 0) {
- proj4_unit = G_store(pszValue);
- continue;
- }
- G_set_key_value(pszToken, pszValue, temp_projinfo);
- }
- if (!pszProj)
- G_warning(_("No projection name! Projection parameters likely to be meaningless."));
- /* -------------------------------------------------------------------- */
- /* Derive the user name for the coordinate system. */
- /* -------------------------------------------------------------------- */
- if (!G_find_key_value("name", *projinfo)) {
- pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0);
- if (!pszProjCS)
- pszProjCS = OSRGetAttrValue(hSRS, "GEOGCS", 0);
- if (pszProjCS) {
- G_set_key_value("name", pszProjCS, *projinfo);
- }
- else if (pszProj) {
- char path[4095];
- char name[80];
-
- /* use name of the projection as name for the coordinate system */
- sprintf(path, "%s/etc/proj/projections", G_gisbase());
- if (G_lookup_key_value_from_file(path, pszProj, name, sizeof(name)) >
- 0)
- G_set_key_value("name", name, *projinfo);
- else
- G_set_key_value("name", pszProj, *projinfo);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Find the GRASS datum name and choose parameters either */
- /* interactively or not. */
- /* -------------------------------------------------------------------- */
- {
- const char *pszDatumNameConst = OSRGetAttrValue(hSRS, "DATUM", 0);
- struct datum_list *list, *listhead;
- char *dum1, *dum2, *pszDatumName;
- int paramspresent =
- GPJ__get_datum_params(temp_projinfo, &dum1, &dum2);
- if (pszDatumNameConst) {
- /* Need to make a new copy of the string so we don't mess
- * around with the memory inside the OGRSpatialReferenceH? */
- pszDatumName = G_store(pszDatumNameConst);
- DatumNameMassage(&pszDatumName);
- G_debug(3, "GPJ_osr_to_grass: pszDatumNameConst: <%s>", pszDatumName);
- list = listhead = read_datum_table();
- while (list != NULL) {
- if (G_strcasecmp(pszDatumName, list->longname) == 0) {
- datum = G_store(list->name);
- break;
- }
- list = list->next;
- }
- free_datum_list(listhead);
- if (datum == NULL) {
- if (paramspresent < 2)
- /* Only give warning if no parameters present */
- G_warning(_("Datum <%s> not recognised by GRASS and no parameters found"),
- pszDatumName);
- }
- else {
- G_set_key_value("datum", datum, *projinfo);
- if (paramspresent < 2) {
- /* If no datum parameters were imported from the OSR
- * object then we should use the set specified by datumtrans */
- char *params, *chosenparams = NULL;
- int paramsets;
- paramsets =
- GPJ_get_default_datum_params_by_name(datum, ¶ms);
- if (paramsets < 0)
- G_warning(_("Datum <%s> apparently recognised by GRASS but no parameters found. "
- "You may want to look into this."), datum);
- else if (datumtrans > paramsets) {
- G_warning(_("Invalid transformation number %d; valid range is 1 to %d. "
- "Leaving datum transform parameters unspecified."),
- datumtrans, paramsets);
- datumtrans = 0;
- }
- if (paramsets > 0) {
- struct gpj_datum_transform_list *tlist, *old;
- tlist = GPJ_get_datum_transform_by_name(datum);
- if (tlist != NULL) {
- do {
- if (tlist->count == datumtrans)
- chosenparams = G_store(tlist->params);
- old = tlist;
- tlist = tlist->next;
- GPJ_free_datum_transform(old);
- } while (tlist != NULL);
- }
- }
- if (chosenparams != NULL) {
- char *paramkey, *paramvalue;
- paramkey = strtok(chosenparams, "=");
- paramvalue = chosenparams + strlen(paramkey) + 1;
- G_set_key_value(paramkey, paramvalue, *projinfo);
- G_free(chosenparams);
- }
- if (paramsets > 0)
- G_free(params);
- }
- }
- G_free(pszDatumName);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Determine an appropriate GRASS ellipsoid name if possible, or */
- /* else just put a and es values into PROJ_INFO */
- /* -------------------------------------------------------------------- */
- if ((datum != NULL) && (GPJ_get_datum_by_name(datum, &dstruct) > 0)) {
- /* Use ellps name associated with datum */
- G_set_key_value("ellps", dstruct.ellps, *projinfo);
- GPJ_free_datum(&dstruct);
- G_free(datum);
- }
- else {
- /* If we can't determine the ellipsoid from the datum, derive it
- * directly from "SPHEROID" parameters in WKT */
- const char *pszSemiMajor = OSRGetAttrValue(hSRS, "SPHEROID", 1);
- const char *pszInvFlat = OSRGetAttrValue(hSRS, "SPHEROID", 2);
- if (pszSemiMajor != NULL && pszInvFlat != NULL) {
- char *ellps = NULL;
- struct ellps_list *list, *listhead;
- double a = atof(pszSemiMajor), invflat = atof(pszInvFlat), flat;
- double es;
- /* Allow for incorrect WKT describing a sphere where InvFlat
- * is given as 0 rather than inf */
- if (invflat > 0)
- flat = 1 / invflat;
- else
- flat = 0;
- es = flat * (2.0 - flat);
- list = listhead = read_ellipsoid_table(0);
- while (list != NULL) {
- /* Try and match a and es against GRASS defined ellipsoids;
- * accept first one that matches. These numbers were found
- * by trial and error and could be fine-tuned, or possibly
- * a direct comparison of IEEE floating point values used. */
- if ((a == list->a || fabs(a - list->a) < 0.1 || fabs(1 - a / list->a) < 0.0000001) &&
- ((es == 0 && list->es == 0) ||
- /* Special case for sphere */
- (invflat == list->rf || fabs(invflat - list->rf) < 0.0000001))) {
- ellps = G_store(list->name);
- break;
- }
- list = list->next;
- }
- if (listhead != NULL)
- free_ellps_list(listhead);
- if (ellps == NULL) {
- /* If we weren't able to find a matching ellps name, set
- * a and es values directly from WKT-derived data */
- char es_str[100];
- G_set_key_value("a", (char *)pszSemiMajor, *projinfo);
- sprintf(es_str, "%.16g", es);
- G_set_key_value("es", es_str, *projinfo);
- }
- else {
- /* else specify the GRASS ellps name for readability */
- G_set_key_value("ellps", ellps, *projinfo);
- G_free(ellps);
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Finally append the detailed projection parameters to the end */
- /* -------------------------------------------------------------------- */
- {
- int i;
- for (i = 0; i < temp_projinfo->nitems; i++)
- G_set_key_value(temp_projinfo->key[i],
- temp_projinfo->value[i], *projinfo);
- G_free_key_value(temp_projinfo);
- }
- G_free(pszProj4);
- /* -------------------------------------------------------------------- */
- /* Set the linear units. */
- /* -------------------------------------------------------------------- */
- *projunits = G_create_key_value();
- if (OSRIsGeographic(hSRS)) {
- /* We assume degrees ... someday we will be wrong! */
- G_set_key_value("unit", "degree", *projunits);
- G_set_key_value("units", "degrees", *projunits);
- G_set_key_value("meters", "1.0", *projunits);
- }
- else {
- char szFormatBuf[256];
- char *pszUnitsName = NULL;
- double dfToMeters;
- char *pszUnitsPlural, *pszStringEnd;
- dfToMeters = OSRGetLinearUnits(hSRS, &pszUnitsName);
- /* the unit name can be arbitrary: the following can be the same
- * us-ft (proj.4 keyword)
- * U.S. Surveyor's Foot (proj.4 name)
- * US survey foot (WKT)
- * Foot_US (WKT)
- */
- /* Workaround for the most obvious case when unit name is unknown */
- if ((G_strcasecmp(pszUnitsName, "unknown") == 0) &&
- (dfToMeters == 1.))
- G_asprintf(&pszUnitsName, "meter");
- if ((G_strcasecmp(pszUnitsName, "metre") == 0))
- G_asprintf(&pszUnitsName, "meter");
- if ((G_strcasecmp(pszUnitsName, "kilometre") == 0))
- G_asprintf(&pszUnitsName, "kilometer");
-
- if (dfToMeters != 1. && proj4_unit) {
- int i;
-
- i = 0;
- while (gpj_units[i].id != NULL) {
- if (strcmp(proj4_unit, gpj_units[i].id) == 0) {
- G_asprintf(&pszUnitsName, "%s", gpj_units[i].name);
- break;
- }
- i++;
- }
- }
- G_set_key_value("unit", pszUnitsName, *projunits);
- /* Attempt at plural formation (WKT format doesn't store plural
- * form of unit name) */
- pszUnitsPlural = G_malloc(strlen(pszUnitsName) + 3);
- strcpy(pszUnitsPlural, pszUnitsName);
- pszStringEnd = pszUnitsPlural + strlen(pszUnitsPlural) - 4;
- if (G_strcasecmp(pszStringEnd, "foot") == 0) {
- /* Special case for foot - change two o's to e's */
- pszStringEnd[1] = 'e';
- pszStringEnd[2] = 'e';
- }
- else if (G_strcasecmp(pszStringEnd, "inch") == 0) {
- /* Special case for inch - add es */
- pszStringEnd[4] = 'e';
- pszStringEnd[5] = 's';
- pszStringEnd[6] = '\0';
- }
- else {
- /* For anything else add an s at the end */
- pszStringEnd[4] = 's';
- pszStringEnd[5] = '\0';
- }
- G_set_key_value("units", pszUnitsPlural, *projunits);
- G_free(pszUnitsPlural);
- sprintf(szFormatBuf, "%.16g", dfToMeters);
- G_set_key_value("meters", szFormatBuf, *projunits);
- }
- if (hSRS != hSRS1)
- OSRDestroySpatialReference(hSRS);
- return 2;
- /* -------------------------------------------------------------------- */
- /* Fallback to returning an ungeoreferenced definition. */
- /* -------------------------------------------------------------------- */
- default_to_xy:
- if (cellhd != NULL) {
- cellhd->proj = PROJECTION_XY;
- cellhd->zone = 0;
- }
- if (*projinfo)
- G_free_key_value(*projinfo);
- *projinfo = NULL;
- *projunits = NULL;
- if (hSRS != NULL && hSRS != hSRS1)
- OSRDestroySpatialReference(hSRS);
- return 1;
- }
- #endif
- /*!
- * \brief Converts a WKT projection description to a GRASS co-ordinate system.
- *
- * \param cellhd Pointer to a GRASS Cell_head structure that will have its
- * projection-related members populated with appropriate values
- * \param projinfo Pointer to a pointer which will have a GRASS Key_Value
- * structure allocated containing a set of GRASS PROJ_INFO values
- * \param projunits Pointer to a pointer which will have a GRASS Key_Value
- * structure allocated containing a set of GRASS PROJ_UNITS values
- * \param wkt Well-known Text (WKT) description of the co-ordinate
- * system to be converted
- * \param datumtrans Index number of datum parameter set to use, 0 to leave
- * unspecified
- *
- * \return 2 if a projected or lat/long co-ordinate system has been
- * defined
- * \return 1 if an unreferenced XY co-ordinate system has
- * been defined
- * \return -1 on error
- */
- int GPJ_wkt_to_grass(struct Cell_head *cellhd, struct Key_Value **projinfo,
- struct Key_Value **projunits, const char *wkt,
- int datumtrans)
- {
- #ifdef HAVE_OGR
- int retval;
- if (wkt == NULL)
- retval =
- GPJ_osr_to_grass(cellhd, projinfo, projunits, NULL, datumtrans);
- else {
- OGRSpatialReferenceH hSRS;
- /* Set finder function for locating OGR csv co-ordinate system tables */
- /* SetCSVFilenameHook(GPJ_set_csv_loc); */
- hSRS = OSRNewSpatialReference(wkt);
- retval =
- GPJ_osr_to_grass(cellhd, projinfo, projunits, hSRS, datumtrans);
- OSRDestroySpatialReference(hSRS);
- }
- return retval;
- #else
- return -1;
- #endif
- }
- #ifdef HAVE_OGR
- /* GPJ_set_csv_loc()
- * 'finder function' for use with OGR SetCSVFilenameHook() function */
- const char *GPJ_set_csv_loc(const char *name)
- {
- const char *gisbase = G_gisbase();
- static char *buf = NULL;
- if (buf != NULL)
- G_free(buf);
- G_asprintf(&buf, "%s%s/%s", gisbase, CSVDIR, name);
- return buf;
- }
- /* The list below is only for files that use a non-standard name for a
- * datum that is already supported in GRASS. The number of entries must be even;
- * they are all in pairs. The first one in the pair is the non-standard name;
- * the second is the GRASS/GDAL name. If a name appears more than once (as for
- * European_Terrestrial_Reference_System_1989) then it means there was more
- * than one non-standard name for it that needs to be accounted for.
- *
- * N.B. The order of these pairs is different from that in
- * ogr/ogrfromepsg.cpp in the GDAL source tree! GRASS uses the EPSG
- * names in its WKT representation except WGS_1984 and WGS_1972 as
- * these shortened versions seem to be standard.
- * Below order:
- * the equivalent name comes first in the pair, and
- * the EPSG name (as used in the GRASS datum.table file) comes second.
- *
- * The datum parameters are stored in
- * ../gis/datum.table # 3 parameters
- * ../gis/datumtransform.table # 7 parameters (requires entry in datum.table)
- *
- * Hint: use GDAL's "testepsg" to identify the canonical name, e.g.
- * testepsg epsg:4674
- */
- static const char *papszDatumEquiv[] = {
- "Militar_Geographische_Institute",
- "Militar_Geographische_Institut",
- "World_Geodetic_System_1984",
- "WGS_1984",
- "World_Geodetic_System_1972",
- "WGS_1972",
- "European_Terrestrial_Reference_System_89",
- "European_Terrestrial_Reference_System_1989",
- "European_Reference_System_1989",
- "European_Terrestrial_Reference_System_1989",
- "ETRS_1989",
- "European_Terrestrial_Reference_System_1989",
- "ETRS89",
- "European_Terrestrial_Reference_System_1989",
- "ETRF_1989",
- "European_Terrestrial_Reference_System_1989",
- "NZGD_2000",
- "New_Zealand_Geodetic_Datum_2000",
- "Monte_Mario_Rome",
- "Monte_Mario",
- "MONTROME",
- "Monte_Mario",
- "Campo_Inchauspe_1969",
- "Campo_Inchauspe",
- "S_JTSK",
- "System_Jednotne_Trigonometricke_Site_Katastralni",
- "S_JTSK_Ferro",
- "Militar_Geographische_Institut",
- "Potsdam_Datum_83",
- "Deutsches_Hauptdreiecksnetz",
- "South_American_1969",
- "South_American_Datum_1969",
- "ITRF_1992",
- "ITRF92",
- NULL
- };
- /************************************************************************/
- /* OGREPSGDatumNameMassage() */
- /* */
- /* Massage an EPSG datum name into WMT format. Also transform */
- /* specific exception cases into WKT versions. */
- /************************************************************************/
- static void DatumNameMassage(char **ppszDatum)
- {
- int i, j;
- char *pszDatum = *ppszDatum;
- G_debug(3, "DatumNameMassage: Raw string found <%s>", (char *)pszDatum);
- /* -------------------------------------------------------------------- */
- /* Translate non-alphanumeric values to underscores. */
- /* -------------------------------------------------------------------- */
- for (i = 0; pszDatum[i] != '\0'; i++) {
- if (!(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
- && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
- && !(pszDatum[i] >= '0' && pszDatum[i] <= '9')) {
- pszDatum[i] = '_';
- }
- }
- /* -------------------------------------------------------------------- */
- /* Remove repeated and trailing underscores. */
- /* -------------------------------------------------------------------- */
- for (i = 1, j = 0; pszDatum[i] != '\0'; i++) {
- if (pszDatum[j] == '_' && pszDatum[i] == '_')
- continue;
- pszDatum[++j] = pszDatum[i];
- }
- if (pszDatum[j] == '_')
- pszDatum[j] = '\0';
- else
- pszDatum[j + 1] = '\0';
- /* -------------------------------------------------------------------- */
- /* Search for datum equivalences. Specific massaged names get */
- /* mapped to OpenGIS specified names. */
- /* -------------------------------------------------------------------- */
- G_debug(3, "DatumNameMassage: Search for datum equivalences of <%s>", (char *)pszDatum);
- for (i = 0; papszDatumEquiv[i] != NULL; i += 2) {
- if (EQUAL(*ppszDatum, papszDatumEquiv[i])) {
- G_free(*ppszDatum);
- *ppszDatum = G_store(papszDatumEquiv[i + 1]);
- break;
- }
- }
- }
- #endif /* HAVE_OGR */
|