[gdal-dev] GDAL 3.7.0 Proj 6.3.1 strange behavior when performing NAD83(EPSG:4152) to NAD83 HARN(EPSG:4269) realization transformation

David Klaus dklaus at carlsonsw.com
Mon Jul 15 11:29:39 PDT 2024


All,

I've cleaned up the code I have as best I can. I removed all the code
specific to our codebase and tried to remove a lot of extraneous settings.
This will still require that the user set a few environment variables that
will be specific to their system. Hopefully the comments I added make it
clear what path folders are required on your system.

Even sent me the following link: https://github.com/OSGeo/PROJ/pull/3510.
The following line from this update stuck out to me:

NAD83 to NAD83(2011) is no longer a null transformation, but actually
chains 4 successive NADCON5 grid based transformations

To me, this suggests that most NAD83 realization transformations were not
implemented until at least Proj4 9.2.0. It does seem like some form of the
NAD83 1986 to NAD83 HARN realization transformation was implemented prior
to this through the HPGN files in the  proj-datumgrid package. But, I
suspect this implementation is inferior to the implementation after Proj4
9.2.0.

So, I suspect Greg is on the right track when he told us to upgrade to the
latest version of Proj4. I'm still not clear which min version of GDAL
would is necessary for compatibility with Proj4 9.2.0+. If anyone knows off
the top of their head, please let me know.

But, I can do some research on this as well,

On Mon, Jul 15, 2024 at 1:30 PM David Klaus <dklaus at carlsonsw.com> wrote:

> All,
>
> If I understand correctly. Before we do anything else, we should try to
> rebuilt our GDAL solution such that it uses at least Proj4 9.2.0, do I have
> that right? Does anyone happen to know the minimum GDAL version compatible
> with Proj4 9.2.0?
>
> P.S. I am still working on the code example to repeat the issue I ran into.
>
> On Mon, Jul 15, 2024 at 1:03 PM Greg Troxel <gdt at lexort.com> wrote:
>
>> David Klaus <dklaus at carlsonsw.com> writes:
>>
>> > Thank you for the input. You don't happen to know where I can find
>> > documentation on these NADCON5 related changes?
>>
>> I would suggest reading the 9.2.0 release notes.
>> There is a link to a merged PR which has further discussion.
>>
>> The tl;dr; is that proj matches NGS tools.  Which is a pretty stunning
>> result.
>>
>>
>
> --
> David Klaus
> Carlson Software
>


-- 
David Klaus
Carlson Software

Disclaimer

The information contained in this communication from the sender is confidential. It is intended solely for use by the recipient and others authorized to receive it. If you are not the recipient, you are hereby notified that any disclosure, copying, distribution or taking action in relation of the contents of this information is strictly prohibited and may be unlawful.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/gdal-dev/attachments/20240715/6a1cdbe9/attachment-0001.htm>
-------------- next part --------------
#include "gdal_priv.h"
#include "ogr_api.h"
#include "ogr_spatialref.h"
#include "cpl_conv.h"

namespace{ // anonymous namespace for functions specific to CsGdalSettings

  // Error handler for redirecting error/debug messages to Output.
  void TestCplErrorHandlerRedirectToOutput(CPLErr cplErr, int errNumber, const char* msgSz){
    std::string cpl_err_str="CE_Unknown";
    switch(cplErr)
    {
    case CE_None:
      cpl_err_str="CE_None";
      break;
    case CE_Debug:
      cpl_err_str="CE_Debug";
      break;
    case CE_Warning:
      cpl_err_str="CE_Warning";
      break;
    case CE_Failure:
      cpl_err_str="CE_Failure";
      break;
    case CE_Fatal:
      cpl_err_str="CE_Fatal";
      break;
    default:
      break;
    }
    char test_message_sz[2056]={'\0'};
    std::snprintf(test_message_sz, 2055, "Error class: %s,\tError no: %d,\tMessage: %s\n", cpl_err_str.c_str(), errNumber, msgSz);
    OutputDebugString(test_message_sz); // Redirect the error message to the global stringstream
  }

  // GETENV_NOTE: _putenv_s() is used to ensure compatibility with getenv(). getenv() operates on environment variables loaded into _environ global (loaded at loads at "process startup.")
  //              SetEnvironmentVariable() affects the environment variables set for this process but does not change _environ. _putenv_s() updates _environ and ensures compatibility w/
  //              genenv().
  void TestSetEnvironmentVariable(const csString& varNameStr, const csString& varValueStr){
    SetEnvironmentVariable(varNameStr, varValueStr);
    _putenv_s(varNameStr, varValueStr); // (See: GETENV_NOTE)
  }

  // Returns path to folder containing all gdal data/proj-data and executables for the current GDAL build.
  const char* TestGetInstallationSharedDataFolder(){
    // Your code here.
    // return .... path to gdal data and proj-data and executables for your GDAL build
  }

  // Returns path to folder to the proj-data folder.
  const char* TestGetInstallationProj4DataFolder(){
    // Your code here.
    // return .... path to proj-data folder
  }

  // Second location that Proj4 can use to look up proj-data information. We use this second folder to
  // store information downloaded from the internet. These files aren't included in our installation.
  // The contents of the proj-datumgrid-1.7 are stored here.
  const char* TestGetDownloadableProj4DataFolder()
  {
    // Your code here
    // return .... path to second proj-data location (not strictly necessary)
  }
}

void TestGdal()
{
  // set environment variables
  std::string shared_data_root_install_path_str=TestGetInstallationSharedDataFolder();
  std::string proj4_data_install_path_str=TestGetInstallationProj4DataFolder();
  csString proj4_data_downloadable_path_str=TestGetDownloadableProj4DataFolder();
  CPLSetConfigOption("GDAL_DATA", shared_data_root_install_path_str.c_str());
  CPLSetConfigOption("GEOTIFF_CSV", shared_data_root_install_path_str.c_str());
  //CPLSetConfigOption("CURL_CA_BUNDLE", CsGdalSettings::GdalConfiguration::GetCurlCABundleFile());
  TestSetEnvironmentVariable("GDAL_DATA", shared_data_root_install_path_str.c_str()); // https://trac.osgeo.org/gdal/wiki/FAQInstallationAndBuilding#WhatisGDAL_DATAenvironmentvariable
  char proj_lib_paths_sz[MAX_PATH*3]={'\0'};
  std::snprintf(proj_lib_paths_sz, MAX_PATH*3-1, "%s;%s", proj4_data_install_path_str.c_str(), proj4_data_downloadable_path_str.Get());
  TestSetEnvironmentVariable("PROJ_LIB", proj_lib_paths_sz);
  CPLSetConfigOption("CPL_DEBUG", "ON");
  TestSetEnvironmentVariable("CPL_DEBUG", "ON"); // This may not be strictly necessary. Defensive coding.
  TestSetEnvironmentVariable("PROJ_DEBUG", "3");
  CPLSetErrorHandler(TestCplErrorHandlerRedirectToOutput); // Redirect debug/error messages to output

  // Register all GDAL drivers
  GDALAllRegister();

  //Generate coordinate transformation from NAD83 1986 to NAD83 HARN.
  OGRSpatialReference nad83_1986_srs;
  nad83_1986_srs.importFromEPSG(4269); // NAD83 1986
  OGRSpatialReference nad83_harn_srs;
  nad83_harn_srs.importFromEPSG(4152); // NAD83 HARN
  OGRCoordinateTransformation* nad83_1986_to_nad83_harn_ct=OGRCreateCoordinateTransformation(&nad83_1986_srs, &nad83_harn_srs);

  // Perform coordinate transformation
  if(nad83_1986_to_nad83_harn_ct!=nullptr){

    // Perform NAD83 1986 to NAD83 HARN for coordiantes in Philadelphia, PA
    double in_philadelphia_lon=-75.165147;
    double in_philadelphia_lat=39.952673;
    double in_philadelphia_elv=0.0;
    double out_philadelphia_lon=in_philadelphia_lon;
    double out_philadelphia_lat=in_philadelphia_lat;
    double out_philadelphia_elv=in_philadelphia_elv;
    nad83_1986_to_nad83_harn_ct->Transform(1, &out_philadelphia_lon, &out_philadelphia_lat, &out_philadelphia_elv); // Results in the following output: "Error class: CE_Debug,	Error no: 0,	Message: PROJ: Using coordinate operation Ballpark geographic offset from NAD83 to NAD83(HARN)"

    // Output results
    char results_sz[2056]={'\0'};
    snprintf(
      results_sz,
      2055,
      "\nIn:   (%.10f,%.10f,%.10f)"
      "\nOut:  (%.10f,%.10f,%.10f)",
      in_philadelphia_lon, in_philadelphia_lat, in_philadelphia_elv,
      out_philadelphia_lon, out_philadelphia_lat, out_philadelphia_elv
    );
    OutputDebugString(results_sz);
    
    // cleanup
    OGRCoordinateTransformation::DestroyCT(nad83_1986_to_nad83_harn_ct);
  }
  
  // cleanup
  CPLFreeConfig();
}


More information about the gdal-dev mailing list