diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index 2d544189db..06e1d36aa0 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -14,7 +14,6 @@ PROJ project or using the library in their own software. quickstart transformations errorhandling - threads reference/index cmake bindings diff --git a/docs/source/development/quickstart.rst b/docs/source/development/quickstart.rst index eefd5ac3ec..5be8564155 100644 --- a/docs/source/development/quickstart.rst +++ b/docs/source/development/quickstart.rst @@ -28,10 +28,9 @@ See the :doc:`reference for more info on data types `. :lines: 43-46 :dedent: 4 -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 ` discusses -this in detail. +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 we demonstrate its use here. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c @@ -39,13 +38,38 @@ this in detail. :dedent: 4 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: +:c:func:`proj_create_crs_to_crs`. + +.. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c + :language: c + :lines: 52-60 + :dedent: 4 + +Here we have set up a transformation from geographic coordinates to UTM zone +32N. + +:c:func:`proj_create_crs_to_crs` takes as its arguments: + +- 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. + +It is recommended to create one threading context per thread used by the +program. This ensures that all :c:type:`PJ` objects created in the same +context will be sharing resources such as error-numbers and loaded grids. + +If you are sure that ``P`` will only be used by a single program thread, you +may pass ``NULL`` for the threading context. This will assign the default +thread context to ``P``. + +The strings for the source and target CRS may be any of: + +- PROJ strings, e.g. ``+proj=longlat +datum=WGS84 +type=crs``, +- CRS identified by their code, e.g. ``EPSG:4326`` or + ``urn:ogc:def:crs:EPSG::4326``, or +- a well-known text (WKT) string, e.g.: + :: GEOGCRS["WGS 84", @@ -67,89 +91,107 @@ by a well-known text (WKT) string: 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 :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. +.. warning:: -.. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c - :language: c - :lines: 52-60 - :dedent: 4 + The use of PROJ strings to describe a CRS is not recommended. One of the + main weaknesses of PROJ strings is their inability to describe a geodetic + datum, other than the few ones hardcoded in the ``+datum`` parameter. + +:c:func:`proj_create_crs_to_crs` will return a pointer to a :c:type:`PJ` +object, or a null pointer in the case of an error. The details of the error +can be retrieved using :c:func:`proj_context_errno`. See :doc:`errorhandling` +for further details. + +Now that we have a normalized transformation object in ``P``, we can use it +with :c:func:`proj_trans` to transform coordinates from the source CRS to the +target CRS, but first we will discuss the interpretation of coordinates. + +By default, a :c:type:`PJ` transformation object accepts coordinates expressed +in the units and axis order of the source CRS, and returns transformed +coordinates in the units and axis order of the target CRS. + +For most geographic CRS, the units will be in 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, the order is the reverse; 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 you prefer to work with a uniform axis order, regardless of the axis orders +mandated by the source and target CRS, you can use the +:c:func:`proj_normalize_for_visualization` function. -: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. +:c:func:`proj_normalize_for_visualization` takes a threading context and an +existing :c:type:`PJ` object, and generates from it a new :c:type:`PJ` that +accepts as input and returns as output coordinates using the traditional GIS +order. That is, longitude followed by latitude, optionally followed by +elevation and time for geographic CRS, and easting followed by northing for +most projected CRS. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c :lines: 65-71 :dedent: 4 -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. +Next we create a :c:type:`PJ_COORD` coordinate object, using the function +:c:func:`proj_coord`. + +The following example creates a coordinate for 55°N 12°E (Copenhagen). + +Because we have normalized the transformation object with +:c:func:`proj_normalize_for_visualization`, the order of coordinates is +longitude followed by latitude, and the units are degrees. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c :lines: 76 :dedent: 4 -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. +Now we are ready to transform the coordinate into UTM zone 32, using the +function :c:func:`proj_trans`. .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c :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. +:c:func:`proj_trans` takes as its arguments: + +- a :c:type:`PJ` transformation object, +- a :c:type:`PJ_DIRECTION` direction, and +- the :c:type:`PJ_COORD` coordinate to transform. + +The direction argument can be one of: + +- ``PJ_FWD`` -- "forward" transformation from source CRS to target CRS. +- ``PJ_IDENT`` -- "identity", return the source coordinate unchanged. +- ``PJ_INV`` -- "inverse" transformation from target CRS to source CRS. + +It returns the new transformed :c:type:`PJ_COORD` coordinate. + +We can perform the transformation in reverse (from UTM zone 32 back to +geographic) as follows: .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 81-82 + :lines: 82-83 :dedent: 4 -Before ending the program the allocated memory needs to be released again: +Before ending the program, we need to release the memory allocated to our +objects: .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c - :lines: 85-86 + :lines: 86-87 :dedent: 4 -A complete compilable version of the above can be seen here: +A complete compilable version of the example code can be seen below: .. literalinclude:: ../../../examples/pj_obs_api_mini_demo.c :language: c diff --git a/docs/source/development/threads.rst b/docs/source/development/threads.rst deleted file mode 100644 index 674f4bd118..0000000000 --- a/docs/source/development/threads.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. _threads: - -================================================================================ -Threads -================================================================================ - -This page is about efforts to make PROJ thread safe. - -Key Thread Safety Issues --------------------------------------------------------------------------------- - -* the global pj_errno variable is shared between threads and makes it - essentially impossible to handle errors safely. Being addressed with the - introduction of the projCtx execution context. -* the datum shift using grid files uses globally shared lists of loaded grid - information. Access to this has been made safe in 4.7.0 with the introduction - of a PROJ mutex used to protect access to these memory structures (see - pj_mutex.c). - -projCtx --------------------------------------------------------------------------------- - -Primarily in order to avoid having pj_errno as a global variable, a "thread -context" structure has been introduced into a variation of the PROJ API for -the 4.8.0 release. The pj_init() and pj_init_plus() functions now have context -variations called pj_init_ctx() and pj_init_plus_ctx() which take a projections -context. - -The projections context can be created with pj_ctx_alloc(), and there is a -global default context used when one is not provided by the application. There -is a pj_ctx\_ set of functions to create, manipulate, query, and destroy -contexts. The contexts are also used now to handle setting debugging mode, and -to hold an error reporting function for textual error and debug messages. The -API looks like: - -:: - - projPJ pj_init_ctx( projCtx, int, char ** ); - projPJ pj_init_plus_ctx( projCtx, const char * ); - - projCtx pj_get_default_ctx(void); - projCtx pj_get_ctx( projPJ ); - void pj_set_ctx( projPJ, projCtx ); - projCtx pj_ctx_alloc(void); - void pj_ctx_free( projCtx ); - int pj_ctx_get_errno( projCtx ); - void pj_ctx_set_errno( projCtx, int ); - void pj_ctx_set_debug( projCtx, int ); - void pj_ctx_set_logger( projCtx, void (*)(void *, int, const char *) ); - void pj_ctx_set_app_data( projCtx, void * ); - void *pj_ctx_get_app_data( projCtx ); - -Multithreaded applications are now expected to create a projCtx per thread -using pj_ctx_alloc(). The context's error handlers, and app data may be -modified if desired, but at the very least each context has an internal error -value accessed with pj_ctx_get_errno() as opposed to looking at pj_errno. - -Note that pj_errno continues to exist, and it is set by pj_ctx_set_errno() (as -well as setting the context specific error number), but pj_errno still suffers -from the global shared problem between threads and should not be used by -multithreaded applications. - -Note that pj_init_ctx(), and pj_init_plus_ctx() will assign the projCtx to the -created projPJ object. Functions like pj_transform(), pj_fwd() and pj_inv() -will use the context of the projPJ for error reporting. - -src/multistresstest.c --------------------------------------------------------------------------------- - -A small multi-threaded test program has been written (src/multistresstest.c) -for testing multithreaded use of PROJ. It performs a series of reprojections -to setup a table expected results, and then it does them many times in several -threads to confirm that the results are consistent. At this time this program -is not part of the builds but it can be built on linux like: - -:: - - gcc -g multistresstest.c .libs/libproj.so -lpthread -o multistresstest - ./multistresstest diff --git a/examples/pj_obs_api_mini_demo.c b/examples/pj_obs_api_mini_demo.c index 3df94e2d78..5cd5efe4d3 100644 --- a/examples/pj_obs_api_mini_demo.c +++ b/examples/pj_obs_api_mini_demo.c @@ -1,6 +1,6 @@ /******************************************************************************* - Tiny test of an evolving new API, demonstrating simple examples of - 2D and 3D transformations. + Simple example code demonstrating use of the proj.h API for 2D coordinate + transformations. The main transformation setup object is PJ, well known from the two former proj APIs (projects.h and proj_api.h) @@ -42,7 +42,7 @@ int main (void) { PJ_CONTEXT *C; PJ *P; - PJ* P_for_GIS; + PJ *norm; PJ_COORD a, b; /* or you may set C=PJ_DEFAULT_CTX if you are sure you will */ @@ -54,35 +54,36 @@ int main (void) { "+proj=utm +zone=32 +datum=WGS84", /* or EPSG:32632 */ NULL); - if (0==P) { - fprintf(stderr, "Oops\n"); + if (0 == P) { + fprintf(stderr, "Failed to create transformation object.\n"); return 1; } /* This will ensure that the order of coordinates for the input CRS */ /* will be longitude, latitude, whereas EPSG:4326 mandates latitude, */ /* longitude */ - P_for_GIS = proj_normalize_for_visualization(C, P); - if( 0 == P_for_GIS ) { - fprintf(stderr, "Oops\n"); + norm = proj_normalize_for_visualization(C, P); + if (0 == norm) { + fprintf(stderr, "Failed to normalize transformation object.\n"); return 1; } proj_destroy(P); - P = P_for_GIS; + P = norm; /* a coordinate union representing Copenhagen: 55d N, 12d E */ /* Given that we have used proj_normalize_for_visualization(), the order of /* coordinates is longitude, latitude, and values are expressed in degrees. */ - a = proj_coord (12, 55, 0, 0); + a = proj_coord(12, 55, 0, 0); /* transform to UTM zone 32, then back to geographical */ - b = proj_trans (P, PJ_FWD, a); - printf ("easting: %.3f, northing: %.3f\n", b.enu.e, b.enu.n); - b = proj_trans (P, PJ_INV, b); - printf ("longitude: %g, latitude: %g\n", b.lp.lam, b.lp.phi); + b = proj_trans(P, PJ_FWD, a); + printf("easting: %.3f, northing: %.3f\n", b.enu.e, b.enu.n); + + b = proj_trans(P, PJ_INV, b); + printf("longitude: %g, latitude: %g\n", b.lp.lam, b.lp.phi); /* Clean up */ - proj_destroy (P); - proj_context_destroy (C); /* may be omitted in the single threaded case */ + proj_destroy(P); + proj_context_destroy(C); /* may be omitted in the single threaded case */ return 0; }