[Git][debian-gis-team/proj][upstream] New upstream version 9.8.1

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Fri Apr 10 14:36:39 BST 2026



Bas Couwenberg pushed to branch upstream at Debian GIS Project / proj


Commits:
86566592 by Bas Couwenberg at 2026-04-10T15:27:39+02:00
New upstream version 9.8.1
- - - - -


15 changed files:

- CITATION.cff
- NEWS.md
- man/man1/cct.1
- man/man1/cs2cs.1
- man/man1/geod.1
- man/man1/gie.1
- man/man1/proj.1
- man/man1/projinfo.1
- man/man1/projsync.1
- src/apps/gie.cpp
- src/release.cpp
- test/CMakeLists.txt
- test/gie/deformation.gie
- + test/gie/epsg_grid.gie
- + test/gie/epsg_no_grid.gie


Changes:

=====================================
CITATION.cff
=====================================
@@ -3,7 +3,7 @@ message: Please cite this software using these metadata or in the CITATION file.
 type: software
 title: PROJ
 version: 9.8.1
-date-released: 2026-04-08
+date-released: 2026-04-10
 doi: 10.5281/zenodo.5884394
 abstract: PROJ is a generic coordinate transformation software that transforms
   geospatial coordinates from one coordinate reference system (CRS) to another.


=====================================
NEWS.md
=====================================
@@ -39,6 +39,9 @@ longer available in PROJ 9.8.1.
   Helps for example for **EPSG:5705** (Baltic 1977 height) to **EPSG:5706** (Caspian depth)
   by using intermediate operation from Baltic 1977 height to Caspian *height*
 
+* gie: various fixes around crs_src/crs_dst support and bootstrap
+  test/gie/epsg_grid.gie and test/gie/epsg_no_grid.gie (#4740)
+
 ## 9.8.0
 
 ### Updates


=====================================
man/man1/cct.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "CCT" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "CCT" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 cct \- Coordinate Conversion and Transformation
 .SH SYNOPSIS


=====================================
man/man1/cs2cs.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "CS2CS" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "CS2CS" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 cs2cs \- Cartographic coordinate system filter
 .SH SYNOPSIS


=====================================
man/man1/geod.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "GEOD" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "GEOD" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 geod \- Geodesic computations
 .SH SYNOPSIS


=====================================
man/man1/gie.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "GIE" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "GIE" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 gie \- The Geospatial Integrity Investigation Environment
 .SH SYNOPSIS


=====================================
man/man1/proj.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "PROJ" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "PROJ" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 proj \- Cartographic projection filter
 .SH SYNOPSIS


=====================================
man/man1/projinfo.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "PROJINFO" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "PROJINFO" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 projinfo \- Geodetic object and coordinate operation queries
 .SH SYNOPSIS


=====================================
man/man1/projsync.1
=====================================
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
 .in \\n[rst2man-indent\\n[rst2man-indent-level]]u
 ..
-.TH "PROJSYNC" "1" "08 Apr 2026" "9.8" "PROJ"
+.TH "PROJSYNC" "1" "10 avril 2026" "9.8" "PROJ"
 .SH NAME
 projsync \- Downloading tool of resource files
 .SH SYNOPSIS


=====================================
src/apps/gie.cpp
=====================================
@@ -104,6 +104,8 @@ Thomas Knudsen, thokn at sdfe.dk, 2017-10-01/2017-10-08
 
 ***********************************************************************/
 
+#define FROM_PROJ_CPP
+
 #include <ctype.h>
 #include <errno.h>
 #include <math.h>
@@ -116,9 +118,13 @@ Thomas Knudsen, thokn at sdfe.dk, 2017-10-01/2017-10-08
 #include "proj.h"
 #include "proj_internal.h"
 #include "proj_strtod.h"
+
+#include <algorithm>
 #include <cmath> /* for isnan */
 #include <math.h>
 
+#include <proj/internal/internal.hpp>
+
 #include "optargpm.h"
 
 /* Package for flexible format I/O - ffio */
@@ -192,6 +198,7 @@ typedef struct {
     char crs_dst[MAX_OPERATION + 1];
     char crs_src[MAX_OPERATION + 1];
     PJ *P;
+    bool crs_dst_is_lat_lon_or_y_x;
     PJ_COORD a, b, e;
     PJ_DIRECTION dir;
     int verbosity;
@@ -561,6 +568,21 @@ static int require_grid(const char *args) {
     const char *grid_filename = column(args, 1);
     grid_info = proj_grid_info(grid_filename);
     if (strlen(grid_info.filename) == 0) {
+
+        if (proj_context_is_network_enabled(nullptr)) {
+            auto dbContext = NS_PROJ::io::DatabaseContext::create();
+            std::string fullFilename, packageName, url;
+            bool directDownload, openLicense, gridAvailable = false;
+            if (dbContext->lookForGridInfo(
+                    grid_filename,
+                    /* considerKnownGridsAsAvailable = */ true, fullFilename,
+                    packageName, url, directDownload, openLicense,
+                    gridAvailable) &&
+                gridAvailable) {
+                return 0;
+            }
+        }
+
         if (T.verbosity > 1) {
             fprintf(T.fout, "Test skipped because of missing grid %s\n",
                     grid_filename);
@@ -644,6 +666,56 @@ static int operation(const char *args) {
     return 0;
 }
 
+static bool isLatOrNorthingFirst(const PJ *crs) {
+    auto crsType = proj_get_type(crs);
+
+    if (crsType == PJ_TYPE_COMPOUND_CRS) {
+        auto horiz_crs = proj_crs_get_sub_crs(nullptr, crs, 0);
+        assert(horiz_crs);
+        bool ret = isLatOrNorthingFirst(horiz_crs);
+        proj_destroy(horiz_crs);
+        return ret;
+    }
+
+    if (crsType != PJ_TYPE_GEOGRAPHIC_2D_CRS &&
+        crsType != PJ_TYPE_GEOGRAPHIC_3D_CRS &&
+        crsType != PJ_TYPE_GEOCENTRIC_CRS && crsType != PJ_TYPE_PROJECTED_CRS) {
+        fprintf(stderr, "Bug in gie.cpp:%d: unsupported CRS type %d!\n",
+                __LINE__, crsType);
+        return false;
+    }
+
+    auto cs = proj_crs_get_coordinate_system(nullptr, crs);
+    assert(cs);
+
+    const char *axisName = "";
+    const char *unitName = "";
+    proj_cs_get_axis_info(nullptr, cs, 0,
+                          &axisName, // name,
+                          nullptr,   // abbrev
+                          nullptr,   // direction
+                          nullptr,   // unit conv factor
+                          &unitName, // unit name
+                          nullptr,   // unit authority
+                          nullptr    // unit code
+    );
+    const bool isLatOrNorthingFirst =
+        NS_PROJ::internal::ci_find(std::string(axisName), "latitude") !=
+            std::string::npos ||
+        NS_PROJ::internal::ci_find(std::string(axisName), "northing") !=
+            std::string::npos;
+    proj_destroy(cs);
+
+    if (strcmp(unitName, "degree") != 0 && strcmp(unitName, "metre") != 0) {
+        // We should add normalization to this unit in expect()
+        fprintf(stderr, "Bug in gie.cpp:%d: unsupported unit %s!\n", __LINE__,
+                unitName);
+        return false;
+    }
+
+    return isLatOrNorthingFirst;
+}
+
 static int crs_to_crs_operation() {
     T.op_id++;
     T.operation_lineno = F->lineno;
@@ -671,6 +743,14 @@ static int crs_to_crs_operation() {
     proj_errno_reset(nullptr);
     proj_context_use_proj4_init_rules(nullptr, T.use_proj4_init_rules);
 
+    T.crs_dst_is_lat_lon_or_y_x = false;
+    PJ *pj_dst = proj_create(nullptr, T.crs_dst);
+    if (!pj_dst) {
+        fprintf(stderr, "Cannot instantiate crs_dst = %s\n", T.crs_dst);
+    }
+    T.crs_dst_is_lat_lon_or_y_x = isLatOrNorthingFirst(pj_dst);
+    proj_destroy(pj_dst);
+
     T.P = proj_create_crs_to_crs(nullptr, T.crs_src, T.crs_dst, nullptr);
 
     strcpy(T.crs_src, "");
@@ -925,18 +1005,6 @@ static int expect_failure_with_errno_message(int expected, int got) {
     return 1;
 }
 
-/* For test purposes, we want to call a transformation of the same */
-/* dimensionality as the number of dimensions given in accept */
-static PJ_COORD expect_trans_n_dim(const PJ_COORD &ci) {
-    if (4 == T.dimensions_given_at_last_accept)
-        return proj_trans(T.P, T.dir, ci);
-
-    if (3 == T.dimensions_given_at_last_accept)
-        return pj_approx_3D_trans(T.P, T.dir, ci);
-
-    return pj_approx_2D_trans(T.P, T.dir, ci);
-}
-
 /*****************************************************************************/
 static int expect(const char *args) {
     /*****************************************************************************
@@ -989,7 +1057,7 @@ static int expect(const char *args) {
         /* Try to carry out the operation - and expect failure */
         ci =
             proj_angular_input(T.P, T.dir) ? torad_coord(T.P, T.dir, T.a) : T.a;
-        co = expect_trans_n_dim(ci);
+        co = proj_trans(T.P, T.dir, ci);
 
         if (expect_failure_with_errno) {
             if (proj_errno(T.P) == expect_failure_with_errno)
@@ -1043,7 +1111,7 @@ static int expect(const char *args) {
 
     /* do the transformation, but mask off dimensions not given in expect-ation
      */
-    co = expect_trans_n_dim(ci);
+    co = proj_trans(T.P, T.dir, ci);
     if (T.dimensions_given < 4)
         co.v[3] = 0;
     if (T.dimensions_given < 3)
@@ -1056,23 +1124,68 @@ static int expect(const char *args) {
                 co.v[1], co.v[2], co.v[3]);
 
 #if 0
-    /* We need to handle unusual axis orders - that'll be an item for version 5.1 */
+    /* We need to handle unusual axis orders when axisswap explicitly present.
+     * Otherwise when using dst_crs code below will take care of that.
+     */
     if (T.P->axisswap) {
         ce = proj_trans (T.P->axisswap, T.dir, ce);
         co = proj_trans (T.P->axisswap, T.dir, co);
     }
 #endif
+
     if (std::isnan(co.v[0]) && std::isnan(ce.v[0])) {
         d = 0.0;
-    } else if (proj_angular_output(T.P, T.dir)) {
+    } else if (proj_angular_output(T.P, T.dir)) { // angular = radians...
+        d = proj_lpz_dist(T.P, ce, co);
+    } else if (proj_degree_output(T.P, T.dir)) {
+        co.v[0] = proj_torad(co.v[0]);
+        co.v[1] = proj_torad(co.v[1]);
+
+        ce.v[0] = proj_torad(ce.v[0]);
+        ce.v[1] = proj_torad(ce.v[1]);
+
+        if (T.crs_dst_is_lat_lon_or_y_x) {
+            std::swap(co.v[0], co.v[1]);
+            std::swap(ce.v[0], ce.v[1]);
+        }
+
         d = proj_lpz_dist(T.P, ce, co);
     } else {
-        d = proj_xyz_dist(co, ce);
+
+        if (T.crs_dst_is_lat_lon_or_y_x) {
+            std::swap(co.v[0], co.v[1]);
+            std::swap(ce.v[0], ce.v[1]);
+        }
+
+        d = proj_xyz_dist(ce, co);
     }
 
     // Test written like that to handle NaN
     if (!(d <= T.tolerance))
         return expect_message(d, args);
+
+    // Somewhat arbitrary temporal threshold but should be fine for all intended
+    // purposes.
+    constexpr double TEMPORAL_THRESHOLD_IN_YEAR = 1e-4;
+    if (T.dimensions_given == 4 &&
+        std::fabs(ce.v[3] - co.v[3]) > TEMPORAL_THRESHOLD_IN_YEAR) {
+        another_failure();
+
+        if (T.verbosity < 0)
+            return 1;
+        if (0 == T.op_ko && T.verbosity < 2)
+            banner(T.operation);
+        fprintf(T.fout, "%s", T.op_ko ? "     -----\n" : delim);
+        fprintf(T.fout, "     FAILURE in %s(%d):\n",
+                opt_strip_path(T.curr_file), (int)F->lineno);
+        fprintf(T.fout, "     expected: %s\n", args);
+        fprintf(T.fout, "     got:      %.12f   %.12f   %.9f   %.9f\n",
+                T.b.v[0], T.b.v[1], T.b.v[2], T.b.v[3]);
+        fprintf(T.fout, "     deviation:  %.4f year, %.4f maximum allowed\n",
+                std::fabs(ce.v[3] - co.v[3]), TEMPORAL_THRESHOLD_IN_YEAR);
+        return 1;
+    }
+
     succs++;
 
     another_success();


=====================================
src/release.cpp
=====================================
@@ -8,6 +8,6 @@
 
 char const pj_release[] = "Rel. " STR(PROJ_VERSION_MAJOR) "." STR(
     PROJ_VERSION_MINOR) "." STR(PROJ_VERSION_PATCH) ", "
-                                                    "April 8th, 2026";
+                                                    "April 10th, 2026";
 
 const char *pj_get_release() { return pj_release; }


=====================================
test/CMakeLists.txt
=====================================
@@ -79,6 +79,7 @@ proj_add_gie_test("guyou" "gie/guyou.gie")
 proj_add_gie_test("peirce_q" "gie/peirce_q.gie")
 proj_add_gie_test("tinshift" "gie/tinshift.gie")
 proj_add_gie_test("spilhaus" "gie/spilhaus.gie")
+proj_add_gie_test("epsg_no_grid" "gie/epsg_no_grid.gie")
 
 if(TIFF_ENABLED)
 proj_add_gie_test("Deformation" "gie/deformation.gie")
@@ -91,6 +92,7 @@ endif()
 
 if(TIFF_ENABLED AND CURL_ENABLED AND RUN_NETWORK_DEPENDENT_TESTS)
 proj_add_gie_network_dependent_test("nkg" "gie/nkg.gie")
+proj_add_gie_network_dependent_test("epsg_grid" "gie/epsg_grid.gie")
 endif()
 
 # GIGS tests. Uncommented tests are expected to fail due to issues with


=====================================
test/gie/deformation.gie
=====================================
@@ -152,7 +152,7 @@ expect      -147.0              64.0                0.0     2011.0
 roundtrip   100
 
 accept      -147.0              64.0                0.0     2011.0
-expect      -147.0              64.0                0.0     2020.0
+expect      -147.0              64.0                0.0     2011.0
 roundtrip   100
 
 -------------------------------------------------------------------------------


=====================================
test/gie/epsg_grid.gie
=====================================
@@ -0,0 +1,32 @@
+### This file must contain only (crs_src, crs_dst) tuples where the best transformation
+### DOES involve the use a grid/json/etc. resource file
+### Otherwise use epsg_no_grid.gie
+
+<gie-strict>
+
+###################################
+#### Generic / worldwide scope ####
+###################################
+
+# Test EGM2008 grid
+crs_src         EPSG:4979       # WGS 84 geographic 3D
+crs_dst         EPSG:9518       # WGS 84 + EGM2008
+tolerance       0.1 mm
+require_grid    us_nga_egm08_25.tif
+
+accept          55.0            12.0            10.0
+expect          55.0            12.0            -27.8257
+
+################
+#### FRANCE ####
+################
+
+crs_src         EPSG:9785       # RGF93 v2b + NGF-IGN69 height
+crs_dst         EPSG:9781       # RGF93 v2b geographic 3D
+tolerance       0.1 mm
+require_grid    fr_ign_RAF20.tif
+
+accept          43.6109         3.8761          0.0
+expect          43.6109         3.8761          49.6904
+
+</gie-strict>


=====================================
test/gie/epsg_no_grid.gie
=====================================
@@ -0,0 +1,61 @@
+### This file must contain only (crs_src, crs_dst) tuples where the best transformation
+### does NOT involve the use a grid/json/etc. resource file
+### Otherwise use epsg_grid.gie
+
+<gie-strict>
+
+###################################
+#### Generic / worldwide scope ####
+###################################
+
+# ETRS89 -> ETRS89/UTM32
+crs_src         EPSG:4258
+crs_dst         EPSG:25832
+tolerance       0.1 mm
+accept          55.0            12.0
+expect          691875.6321     6098907.8250
+
+# WGS 84 geographic 3D -> WGS 84 geocentric
+crs_src         EPSG:4979
+crs_dst         EPSG:4978
+tolerance       0.1 mm
+accept          55.0            12.0            10.0
+expect          3586475.2672    762328.8513     5201391.7147
+
+# WGS 84 geocentric -> WGS 84 geographic 3D
+crs_src         EPSG:4979
+crs_dst         EPSG:4978
+tolerance       0.1 mm
+expect          3586475.2672    762328.8513     5201391.7147
+accept          55.0            12.0            10.0
+
+###################
+#### AUSTRALIA ####
+###################
+
+# GDA2020 -> ITRF2014, using EPSG:8049 "ITRF2014 to GDA2020 (1)" 15-parameter Helmert with 2020.0 central epoch
+crs_src         EPSG:7843       # GDA2020
+crs_dst         EPSG:7912       # ITRF2014
+tolerance       0.1 mm
+accept          -33.8623        151.2077        0.0      2020.0
+expect          -33.8623        151.2077        0.0      2020.0
+
+crs_src         EPSG:7843       # GDA2020
+crs_dst         EPSG:7912       # ITRF2014
+tolerance       0.1 mm
+accept          -33.8623        151.2077        0.0      2026.0
+expect          -33.862297056   151.207701181  -0.00101  2026.0
+
+###################
+###### FINLAND ####
+###################
+
+# Test northing, easting output (actually more a gie test itself, than a EPSG one)
+crs_src         EPSG:4123       # Finland KKJ
+crs_dst         EPSG:2393       # Finland YKJ Northing, Easting
+
+tolerance       0.1 mm
+accept          60.1699         24.9384
+expect          6674944.7742    3385559.8151
+
+</gie-strict>



View it on GitLab: https://salsa.debian.org/debian-gis-team/proj/-/commit/86566592ed1279c03caa04da8dfd7284bfb39ce2

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/proj/-/commit/86566592ed1279c03caa04da8dfd7284bfb39ce2
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20260410/d92fd79d/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list