aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrendan Jurd <direvus@gmail.com>2021-09-27 17:17:58 +1000
committergithub-actions[bot] <github-actions[bot]@users.noreply.github.com>2021-09-27 07:18:25 +0000
commite33ddabcf8866731b5360a3db2c7552229a48a41 (patch)
tree6194405ff994c1f5aaa3738042487b89601e59aa
parent15a619c4e56c53d36ab6c9ea458b603b215c87fa (diff)
downloadPROJ-e33ddabcf8866731b5360a3db2c7552229a48a41.tar.gz
PROJ-e33ddabcf8866731b5360a3db2c7552229a48a41.zip
DOC: Refresh Development/Quickstart and remove Development/Threads (#2863)
* DOC: Refresh Development/Quickstart and remove Development/Threads The document Development/Threads was severely out of date, and was focussed on contrasting the current API with an old API that was deprecated several years ago, and removed from the current PROJ earlier this year. Update Development/Quickstart to give more information about the use of threading context, as a replacement for the content that was previously in Threads. Also give the example code examples/pj_obs_api_mini_demo.c a cleanup pass to make it at least internally consistent with its own code style. The header comments of the example code are still, much like the Threads document, fixated on comparing proj.h against proj_api.h, which is an interesting historical curio to be sure, but probably doesn't need to persist here. It might be worth cleaning this up further as a separate exercise. Fixes #2451
-rw-r--r--docs/source/development/index.rst1
-rw-r--r--docs/source/development/quickstart.rst168
-rw-r--r--docs/source/development/threads.rst79
-rw-r--r--examples/pj_obs_api_mini_demo.c33
4 files changed, 122 insertions, 159 deletions
diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst
index 2d544189..06e1d36a 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 eefd5ac3..5be85641 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 <reference/datatypes>`.
: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 <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 674f4bd1..00000000
--- 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 3df94e2d..5cd5efe4 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;
}