diff options
Diffstat (limited to 'docs/source/development')
| -rw-r--r-- | docs/source/development/migration.rst | 187 | ||||
| -rw-r--r-- | docs/source/development/quickstart.rst | 113 | ||||
| -rw-r--r-- | docs/source/development/reference/functions.rst | 69 |
3 files changed, 306 insertions, 63 deletions
diff --git a/docs/source/development/migration.rst b/docs/source/development/migration.rst index 99143f20..df622ecb 100644 --- a/docs/source/development/migration.rst +++ b/docs/source/development/migration.rst @@ -1,6 +1,151 @@ .. _API_migration: ================================================================================ +Version 4 to 6 API Migration +================================================================================ + +This is a transition guide for developers wanting to migrate their code to use +PROJ version 6. + +Code example +############################################################################### + +The difference between the old and new API is shown here with a few examples. Below +we implement the same program with the two different API's. The program reads +input longitude and latitude from the command line and convert them to +projected coordinates with the Mercator projection. + +We start by writing the program for PROJ 4: + +.. code-block:: C + + #include <proj_api.h> + + main(int argc, char **argv) { + projPJ pj_merc, pj_latlong; + double x, y; + + if (!(pj_longlat = pj_init_plus("+proj=longlat +ellps=clrk66")) ) + return 1; + if (!(pj_merc = pj_init_plus("+proj=merc +datum=clrk66 +lat_ts=33")) ) + return 1; + + while (scanf("%lf %lf", &x, &y) == 2) { + x *= DEG_TO_RAD; /* longitude */ + y *= DEG_TO_RAD; /* latitude */ + p = pj_transform(pj_longlat, pj_merc, 1, 1, &x, &y, NULL ); + printf("%.2f\t%.2f\n", x, y); + } + + pj_free(pj_longlat); + pj_free(pj_merc); + + return 0; + } + +The same program implemented using PROJ 6: + +.. code-block:: C + + #include <proj.h> + + main(int argc, char **argv) { + PJ *P; + PJ_COORD c; + + /* NOTE: the use of PROJ strings to describe CRS is strongly discouraged */ + /* in PROJ 6, as PROJ strings are a poor way of describing a CRS, and */ + /* more precise its geodetic datum. */ + /* Use of codes provided by authorities (such as "EPSG:4326", etc...) */ + /* or WKT strings will bring the full power of the "transformation */ + /* engine" used by PROJ to determine the best transformation(s) between */ + /* two CRS. */ + P = proj_create_crs_to_crs(PJ_DEFAULT_CTX, + "+proj=longlat +ellps=clrs66", + "+proj=merc +ellps=clrk66 +lat_ts=33", + NULL); + if (P==0) + return 1; + + { + /* For that particular use case, this is not needed. */ + /* proj_normalize_for_visualization() ensures that the coordinate */ + /* order expected and returned by proj_trans() will be longitude, */ + /* latitude for geographic CRS, and easting, northing for projected */ + /* CRS. If instead of using PROJ strings as above, "EPSG:XXXX" codes */ + /* had been used, this might had been necessary. */ + PJ* P_for_GIS = proj_normalize_for_visualization(C, P); + if( 0 == P_for_GIS ) { + proj_destroy(P); + return 1; + } + proj_destroy(P); + P = P_for_GIS; + } + + while (scanf("%lf %lf", &c.lp.lam, &c.lp.phi) == 2) { + /* No need to convert to radian */ + c = proj_trans(P, PJ_FWD, c); + printf("%.2f\t%.2f\n", c.xy.x, c.xy.y); + } + + proj_destroy(P); + } + + +Function mapping from old to new API +############################################################################### + ++---------------------------------------+-------------------------------------------------+ +| Old API functions | New API functions | ++=======================================+=================================================+ +| pj_fwd | :c:func:`proj_trans` | ++---------------------------------------+-------------------------------------------------+ +| pj_inv | :c:func:`proj_trans` | ++---------------------------------------+-------------------------------------------------+ +| pj_fwd3 | :c:func:`proj_trans` | ++---------------------------------------+-------------------------------------------------+ +| pj_inv3 | :c:func:`proj_trans` | ++---------------------------------------+-------------------------------------------------+ +| pj_transform | :c:func:`proj_create_crs_to_crs` + | +| | (:c:func:`proj_normalize_for_visualization` +) | +| | :c:func:`proj_trans`, | +| | :c:func:`proj_trans_array` or | +| | :c:func:`proj_trans_generic` | ++---------------------------------------+-------------------------------------------------+ +| pj_init | :c:func:`proj_create` / | +| | :c:func:`proj_create_crs_to_crs` | ++---------------------------------------+-------------------------------------------------+ +| pj_init | :c:func:`proj_create` / | +| | :c:func:`proj_create_crs_to_crs` | ++---------------------------------------+-------------------------------------------------+ +| pj_free | :c:func:`proj_destroy` | ++---------------------------------------+-------------------------------------------------+ +| pj_is_latlong | :c:func:`proj_get_type` | ++---------------------------------------+-------------------------------------------------+ +| pj_is_geocent | :c:func:`proj_get_type` | ++---------------------------------------+-------------------------------------------------+ +| pj_get_def | :c:func:`proj_pj_info` | ++---------------------------------------+-------------------------------------------------+ +| pj_latlong_from_proj | *No direct equivalent*, but can be accomplished | +| | by chaining :c:func:`proj_create`, | +| | :c:func:`proj_crs_get_horizontal_datum` and | +| | :c:func:`proj_create_geographic_crs_from_datum` | ++---------------------------------------+-------------------------------------------------+ +| pj_set_finder | :c:func:`proj_context_set_file_finder` | ++---------------------------------------+-------------------------------------------------+ +| pj_set_searchpath | :c:func:`proj_context_set_search_paths` | ++---------------------------------------+-------------------------------------------------+ +| pj_deallocate_grids | *No equivalent* | ++---------------------------------------+-------------------------------------------------+ +| pj_strerrno | *No equivalent* | ++---------------------------------------+-------------------------------------------------+ +| pj_get_errno_ref | :c:func:`proj_errno` | ++---------------------------------------+-------------------------------------------------+ +| pj_get_release | :c:func:`proj_info` | ++---------------------------------------+-------------------------------------------------+ + +================================================================================ Version 4 to 5 API Migration ================================================================================ @@ -66,7 +211,7 @@ Code example The difference between the old and new API is shown here with a few examples. Below we implement the same program with the two different API's. The program reads -input latitude and longitude from the command line and convert them to +input longitude and latitude from the command line and convert them to projected coordinates with the Mercator projection. We start by writing the program for PROJ v. 4: @@ -76,21 +221,24 @@ We start by writing the program for PROJ v. 4: #include <proj_api.h> main(int argc, char **argv) { - projPJ pj_merc, pj_latlong; + projPJ pj_merc, pj_longlat; double x, y; - if (!(pj_merc = pj_init_plus("+proj=merc +ellps=clrk66 +lat_ts=33")) ) + if (!(pj_longlat = pj_init_plus("+proj=longlat +ellps=clrk66")) ) return 1; - if (!(pj_latlong = pj_init_plus("+proj=latlong +ellps=clrk66")) ) + if (!(pj_merc = pj_init_plus("+proj=merc +ellps=clrk66 +lat_ts=33")) ) return 1; while (scanf("%lf %lf", &x, &y) == 2) { - x *= DEG_TO_RAD; - y *= DEG_TO_RAD; - p = pj_transform(pj_latlong, pj_merc, 1, 1, &x, &y, NULL ); + x *= DEG_TO_RAD; /* longitude */ + y *= DEG_TO_RAD; /* latitude */ + p = pj_transform(pj_longlat, pj_merc, 1, 1, &x, &y, NULL ); printf("%.2f\t%.2f\n", x, y); } + pj_free(pj_longlat); + pj_free(pj_merc); + return 0; } @@ -115,6 +263,7 @@ The same program implemented using PROJ v. 5: printf("%.2f\t%.2f\n", c.xy.x, c.xy.y); } + proj_destroy(P); } Looking at the two different programs, there's a few immediate @@ -155,27 +304,27 @@ Function mapping from old to new API +---------------------------------------+---------------------------------------+ | Old API functions | New API functions | +=======================================+=======================================+ -| pj_fwd | proj_trans | +| pj_fwd | :c:func:`proj_trans` | +---------------------------------------+---------------------------------------+ -| pj_inv | proj_trans | +| pj_inv | :c:func:`proj_trans` | +---------------------------------------+---------------------------------------+ -| pj_fwd3 | proj_trans | +| pj_fwd3 | :c:func:`proj_trans` | +---------------------------------------+---------------------------------------+ -| pj_inv3 | proj_trans | +| pj_inv3 | :c:func:`proj_trans` | +---------------------------------------+---------------------------------------+ | pj_transform | proj_trans_array or proj_trans_generic| +---------------------------------------+---------------------------------------+ -| pj_init | proj_create | +| pj_init | :c:func:`proj_create` | +---------------------------------------+---------------------------------------+ -| pj_init_plus | proj_create | +| pj_init_plus | :c:func:`proj_create` | +---------------------------------------+---------------------------------------+ -| pj_free | proj_destroy | +| pj_free | :c:func:`proj_destroy` | +---------------------------------------+---------------------------------------+ -| pj_is_latlong | proj_angular_output | +| pj_is_latlong | :c:func:`proj_angular_output` | +---------------------------------------+---------------------------------------+ -| pj_is_geocent | proj_angular_outout | +| pj_is_geocent | :c:func:`proj_angular_output` | +---------------------------------------+---------------------------------------+ -| pj_get_def | proj_pj_info | +| pj_get_def | :c:func:`proj_pj_info` | +---------------------------------------+---------------------------------------+ | pj_latlong_from_proj | *No equivalent* | +---------------------------------------+---------------------------------------+ @@ -187,7 +336,7 @@ Function mapping from old to new API +---------------------------------------+---------------------------------------+ | pj_strerrno | *No equivalent* | +---------------------------------------+---------------------------------------+ -| pj_get_errno_ref | proj_errno | +| pj_get_errno_ref | :c:func:`proj_errno` | +---------------------------------------+---------------------------------------+ -| pj_get_release | proj_info | +| pj_get_release | :c:func:`proj_info` | +---------------------------------------+---------------------------------------+ diff --git a/docs/source/development/quickstart.rst b/docs/source/development/quickstart.rst index 960cddbf..d53d98fd 100644 --- a/docs/source/development/quickstart.rst +++ b/docs/source/development/quickstart.rst @@ -25,69 +25,128 @@ See the :doc:`reference for more info on data types <reference/datatypes>`. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 43-45 + :lines: 43-46 :dedent: 4 -For use in multi-threaded programs the ``PJ_CONTEXT`` threading-context is used. +For use in multi-threaded programs the :c:type:`PJ_CONTEXT` threading-context is used. In this particular example it is not needed, but for the sake of completeness it created here. The section on :doc:`threads <threads>` discusses this in detail. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 48 + :lines: 50 :dedent: 4 -Next we create the ``PJ`` transformation object ``P`` with the function -``proj_create``. ``proj_create`` takes the threading context ``C`` created above, -and a proj-string that defines the desired transformation. Here we transform -from geodetic coordinate to UTM zone 32N. +Next we create the :c:type:`PJ` transformation object ``P`` with the function +:c:func:`proj_create_crs_to_crs`. :c:func:`proj_create_crs_to_crs` takes the threading context ``C`` +created above, a string that describes the source coordinate reference system (CRS), +a string that describes the target CRS and an optional description of the area of +use. +The strings for the source or target CRS may be PROJ strings (``+proj=longlat +datum=WGS84``), +CRS identified by their code (``EPSG:4326`` or ``urn:ogc:def:crs:EPSG::4326``) or +by a well-known text (WKT) string ( +:: + + GEOGCRS["WGS 84", + DATUM["World Geodetic System 1984", + ELLIPSOID["WGS 84",6378137,298.257223563, + LENGTHUNIT["metre",1]]], + PRIMEM["Greenwich",0, + ANGLEUNIT["degree",0.0174532925199433]], + CS[ellipsoidal,2], + AXIS["geodetic latitude (Lat)",north, + ORDER[1], + ANGLEUNIT["degree",0.0174532925199433]], + AXIS["geodetic longitude (Lon)",east, + ORDER[2], + ANGLEUNIT["degree",0.0174532925199433]], + USAGE[ + SCOPE["unknown"], + AREA["World"], + BBOX[-90,-180,90,180]], + ID["EPSG",4326]] + +). +The use of PROJ strings to describe a CRS is considered as legacy (one of the +main weakness of PROJ strings is their inability to describe a geodetic datum, +other than the few ones hardcoded in the ``+datum`` parameter). +Here we transform from geographic coordinates to UTM zone 32N. It is recommended to create one threading-context per thread used by the program. -This ensures that all ``PJ`` objects created in the same context will be sharing -resources such as error-numbers and loaded grids. -In case the creation of the ``PJ`` object fails an error message is displayed and -the program returns. See :doc:`errorhandling` for further +This ensures that all :c:type:`PJ` objects created in the same context will be +sharing resources such as error-numbers and loaded grids. +In case the creation of the :c:type:`PJ` object fails an error message is +displayed and the program returns. See :doc:`errorhandling` for further details. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 50-52 + :lines: 52-60 :dedent: 4 -PROJ uses it's own data structures for handling coordinates. Here we use a -``PJ_COORD`` which is easily assigned with the function ``proj_coord``. Note -that the input values are converted to radians with ``proj_torad``. This is -necessary since PROJ is using radians internally. See :doc:`transformations` -for further details. +:c:func:`proj_create_crs_to_crs` creates a transformation object, which accepts +coordinates expressed in the units and axis order of the definition of the +source CRS, and return transformed coordinates in the units and axis order of +the definition of the target CRS. +For almost most geographic CRS, the units will be in most cases degrees (in +rare cases, such as EPSG:4807 / NTF (Paris), this can be grads). For geographic +CRS defined by the EPSG authority, the order of coordinates is latitude first, +longitude second. When using a PROJ string, on contrary the order will be +longitude first, latitude second. +For projected CRS, the units may vary (metre, us-foot, etc..). For projected +CRS defined by the EPSG authority, and with EAST / NORTH directions, the order +might be easting first, northing second, or the reverse. When using a PROJ string, +the order will be easting first, northing second, except if the ``+axis`` +parameter modifies it. + +If for the needs of your software, you want +a uniform axis order (and thus do not care about axis order mandated by the +authority defining the CRS), the :c:func:`proj_normalize_for_visualization` +function can be used to modify the PJ* object returned by +:c:func:`proj_create_crs_to_crs` so that it accepts as input and returns as +output coordinates using the traditional GIS order, that is longitude, latitude +(followed by elevation, time) for geographic CRS and easting, northing for most +projected CRS. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 56 + :lines: 65-71 :dedent: 4 -The coordinate defined above is transformed with ``proj_trans_coord``. For this -a ``PJ`` object, a transformation direction (either forward or inverse) and the -coordinate is needed. The transformed coordinate is returned in ``b``. -Here the forward (``PJ_FWD``) transformation from geodetic to UTM is made. +PROJ uses its own data structures for handling coordinates. Here we use a +:c:type:`PJ_COORD` which is easily assigned with the function :c:func:`proj_coord`. +When using +proj=longlat, the order of coordinates is longitude, latitude, +and values are expressed in degrees. If you used instead a EPSG geographic CRS, +like EPSG:4326 (WGS84), it would be latitude, longitude. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 59-60 + :lines: 76 :dedent: 4 -The inverse transformation (UTM to geodetic) is done similar to above, -this time using ``PJ_INV`` as the direction. +The coordinate defined above is transformed with :c:func:`proj_trans`. For this +a :c:type:`PJ` object, a transformation direction (either forward or inverse) +and the coordinate is needed. The transformed coordinate is returned in ``b``. +Here the forward (:c:type:`PJ_FWD`) transformation from geographic to UTM is made. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 61-62 + :lines: 79-80 + :dedent: 4 + +The inverse transformation (UTM to geographic) is done similar to above, +this time using :c:type:`PJ_INV` as the direction. + +.. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c + :language: c + :lines: 81-82 :dedent: 4 Before ending the program the allocated memory needs to be released again: .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 65-66 + :lines: 85-86 :dedent: 4 diff --git a/docs/source/development/reference/functions.rst b/docs/source/development/reference/functions.rst index 4052ff82..64a4e8ca 100644 --- a/docs/source/development/reference/functions.rst +++ b/docs/source/development/reference/functions.rst @@ -29,9 +29,17 @@ paragraph for more details. .. c:function:: PJ* proj_create(PJ_CONTEXT *ctx, const char *definition) - Create a transformation object, or a CRS object, from a proj-string, - a WKT string, or object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", - "urn:ogc:def:coordinateOperation:EPSG::1671"). + Create a transformation object, or a CRS object, from: + + - a proj-string, + - a WKT string, + - an object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", + "urn:ogc:def:coordinateOperation:EPSG::1671"), + - a OGC URN combining references for compound coordinate reference systems + (e.g "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" or custom abbreviated + syntax "EPSG:2393+5717"), + - a OGC URN combining references for concatenated operations + (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618") Example call: @@ -110,7 +118,8 @@ paragraph for more details. - the name of a CRS as found in the PROJ database, e.g "WGS84", "NAD27", etc. - - more generally any string accepted by :c:func:`proj_create` + - more generally any string accepted by :c:func:`proj_create` representing + a CRS An "area of use" can be specified in area. When it is supplied, the more accurate transformation between two given systems can be chosen. @@ -144,6 +153,25 @@ paragraph for more details. :type `area`: PJ_AREA :returns: :c:type:`PJ*` +.. c:function:: PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ* obj) + + .. versionadded:: 6.1.0 + + Returns a PJ* object whose axis order is the one expected for + visualization purposes. + + The input object must be a coordinate operation, that has been created with + proj_create_crs_to_crs(). + If the axis order of its source or target CRS is northing,easting, then an + axis swap operation will be inserted. + + The returned :c:type:`PJ`-pointer should be deallocated with :c:func:`proj_destroy`. + + :param PJ_CONTEXT* ctx: Threading context. + :param `obj`: Object of type CoordinateOperation + :returns: :c:type:`PJ*` + + .. c:function:: PJ* proj_destroy(PJ *P) Deallocate a :c:type:`PJ` transformation object. @@ -221,10 +249,16 @@ Coordinate transformation 3. of length one, i.e. a constant, which will be treated as a fully populated array of that constant value + .. note:: Even though he coordinate components are named :c:data:`x`, :c:data:`y`, + :c:data:`z` and :c:data:`t`, axis ordering of the to and from CRS + is respected. Transformations exhibit the same behaviour + as if they were gathered in a :c:type:`PJ_COORD` struct. + + The strides, :c:data:`sx`, :c:data:`sy`, :c:data:`sz`, :c:data:`st`, represent the step length, in bytes, between consecutive elements of the corresponding array. This makes it possible for - :c:func:`proj_transform` to handle transformation of a large class of application + :c:func:`proj_trans_generic` to handle transformation of a large class of application specific data structures, without necessarily understanding the data structure format, as in: @@ -250,21 +284,22 @@ Coordinate transformation 0, 0 /* and the time is the constant 0.00 s */ ); - This is similar to the inner workings of the deprecated pj_transform function, but the - stride functionality has been generalized to work for any size of basic unit, - not just a fixed number of doubles. + This is similar to the inner workings of the deprecated :c:func:`pj_transform` + function, but the stride functionality has been generalized to work for any + size of basic unit, not just a fixed number of doubles. In most cases, the stride will be identical for x, y, z, and t, since they will - typically be either individual arrays (stride = sizeof(double)), or strided - views into an array of application specific data structures (stride = sizeof (...)). + typically be either individual arrays (``stride = sizeof(double)``), or strided + views into an array of application specific data structures (``stride = sizeof (...)``). But in order to support cases where :c:data:`x`, :c:data:`y`, :c:data:`z`, and :c:data:`t` come from heterogeneous sources, individual strides, :c:data:`sx`, :c:data:`sy`, :c:data:`sz`, :c:data:`st`, are used. - .. note:: Since :c:func:`proj_transform` does its work *in place*, this means that even the - supposedly constants (i.e. length 1 arrays) will return from the call in altered - state. Hence, remember to reinitialize between repeated calls. + .. note:: Since :c:func:`proj_trans_generic` does its work *in place*, + this means that even the supposedly constants (i.e. length 1 arrays) + will return from the call in altered state. Hence, remember to + reinitialize between repeated calls. :param PJ* P: Transformation object :param `direction`: Transformation direction @@ -631,23 +666,23 @@ Various .. c:function:: int proj_angular_input (PJ *P, enum PJ_DIRECTION dir) - Check if a operation expects angular input. + Check if a operation expects input in radians or not. :param `P`: Transformation object :type `P`: const PJ* :param `direction`: Starting direction of transformation :type `direction`: PJ_DIRECTION - :returns: :c:type:`int` 1 if angular input is expected, otherwise 0 + :returns: :c:type:`int` 1 if input units is expected in radians, otherwise 0 .. c:function:: int proj_angular_output (PJ *P, enum PJ_DIRECTION dir) - Check if an operation returns angular output. + Check if an operation returns output in radians or not. :param `P`: Transformation object :type `P`: const PJ* :param `direction`: Starting direction of transformation :type `direction`: PJ_DIRECTION - :returns: :c:type:`int` 1 if angular output is returned, otherwise 0 + :returns: :c:type:`int` 1 if output units is expected in radians, otherwise 0 C API for ISO-19111 functionality +++++++++++++++++++++++++++++++++ |
