ThinkGeo.com    |     Documentation    |     Premium Support

Projection issue with ProjectionConverter and UnmanagedProjectionConverter for latest EPSG code

Hi

I’ve attempted to use ProjectionConverter for projecting points from WGS84 to the British National Grid. It functions correctly with the EPSG code, but not when utilizing the Proj string.

Check Over EPSG:27700 OSGB36 / British National Grid
Success in ProjectionConverter when using EPSG code.
Error in ProjectionConverter when using PROJ string. Distance Difference= 121.72881056236967
Success in UnmanagedProjectionConverter when using EPSG code.
Error in UnmanagedProjectionConverter when using PROJ string. Distance Difference= 121.7288105637554

The discrepancy when using Proj4 is approximately 120 meters compared to the results from EPSG.IO, whereas using the Code shows no difference.

However, the main issue is our plan to support the projection for the latest EPSG code, such as EPSG:8379 NAD83 / NCRS Las Vegas (m). We are aware that this is not supported by ThinkGeo.ProjectionConverter, so we opted to obtain the Proj string from GDAL and then use the ProjectionConverter by passing the Proj string instead of the code. Consequently, while passing the code resulted in an exception, using the Proj string led to a significant discrepancy when comparing the transformation of the Point from WGS84 to EPSG:8379 with EPSG.IO.
Based on the information we found in the forum, we chose to use the UnmanagedProjectionConverter, which utilizes GDAL in the background. However, we encountered the same issue. Upon examining the GDAL dependency, I discovered that we were using an older version that does not support 8379.

Exception in creating ProjectionConverter when using EPSG code.
Error in ProjectionConverter when using PROJ string. Distance Difference= 416967.8247974478
ERROR 6: EPSG PCS/GCS code 8379 not found in EPSG support files.  Is this a valid EPSG coordinate system?
Exception in creating UnmanagedProjectionConverter when using EPSG code.
Error in UnmanagedProjectionConverter when using PROJ string. Distance Difference= 416967.8247974526

Could you please advise us on how to support the latest projection in our product?

P.S: The sample project is attached to this topic for further investigation.
CheckThinkGeoProjection.zip (5.0 KB)

internal abstract class CheckOverProjection
{
    //The PROJ strings is come from GDAL latest version
    private const string PROJ_4326 = "+proj=longlat +datum=WGS84 +no_defs";
    

    public void Check()
    {
        ProjectionConverterWithCode();
        ProjectionConverterWithProjString();
        UnmanagedProjectionConverterWithCode();
        UnmanagedProjectionConverterWithProjString();
    }

    protected abstract string TargetPROJ { get; }
    protected abstract int TargetEPSGCode { get; }
    protected abstract PointShape PointInWGS { get; }
    protected abstract PointShape ExpectedProjectedPoint { get; }

    private void ProjectionConverterWithCode()
    {
        try
        {
            var projectionConverter = new ProjectionConverter(4326, TargetEPSGCode);
            projectionConverter.Open();
            var projectedPoint = projectionConverter.ConvertToExternalProjection(PointInWGS);
            var distanceDiff = ExpectedProjectedPoint.GetDistanceTo(projectedPoint, GeographyUnit.Meter, DistanceUnit.Meter);
            if (distanceDiff > 2)
            {
                Console.WriteLine($"Error in ProjectionConverter when using EPSG code. Distance Difference= {distanceDiff}");
            }
            else
            {
                Console.WriteLine("Success in ProjectionConverter when using EPSG code.");
            }

        }
        catch (Exception)
        {
            Console.WriteLine($"Exception in creating ProjectionConverter when using EPSG code.");
        }

    }

    private void ProjectionConverterWithProjString()
    {
        try
        {
            var projectionConverter = new ProjectionConverter(PROJ_4326, TargetPROJ);
            projectionConverter.Open();
            var projectedPoint = projectionConverter.ConvertToExternalProjection(PointInWGS);
            var distanceDiff = ExpectedProjectedPoint.GetDistanceTo(projectedPoint, GeographyUnit.Meter, DistanceUnit.Meter);
            if (distanceDiff > 2)
            {
                Console.WriteLine($"Error in ProjectionConverter when using PROJ string. Distance Difference= {distanceDiff}");
            }
            else
            {
                Console.WriteLine("Success in ProjectionConverter when PROJ string.");
            }
        }
        catch (Exception)
        {
            Console.WriteLine($"Exception in creating ProjectionConverter when using PROJ string.");
        }
    }

    private void UnmanagedProjectionConverterWithCode()
    {
        try
        {
            var projectionConverter = new UnmanagedProjectionConverter(4326, TargetEPSGCode);
            projectionConverter.Open();
            var projectedPoint = projectionConverter.ConvertToExternalProjection(PointInWGS);
            var distanceDiff = ExpectedProjectedPoint.GetDistanceTo(projectedPoint, GeographyUnit.Meter, DistanceUnit.Meter);
            if (distanceDiff > 2)
            {
                Console.WriteLine($"Error in UnmanagedProjectionConverter when using EPSG code. Distance Difference= {distanceDiff}");
            }
            else
            {
                Console.WriteLine("Success in UnmanagedProjectionConverter when using EPSG code.");
            }
        }
        catch (Exception)
        {
            Console.WriteLine($"Exception in creating UnmanagedProjectionConverter when using EPSG code.");
        }
    }

    private void UnmanagedProjectionConverterWithProjString()
    {
        try
        {
            var projectionConverter = new UnmanagedProjectionConverter(PROJ_4326, TargetPROJ);
            projectionConverter.Open();
            var projectedPoint = projectionConverter.ConvertToExternalProjection(PointInWGS);
            var distanceDiff = ExpectedProjectedPoint.GetDistanceTo(projectedPoint, GeographyUnit.Meter, DistanceUnit.Meter);
            if (distanceDiff > 2)
            {
                Console.WriteLine($"Error in UnmanagedProjectionConverter when using PROJ string. Distance Difference= {distanceDiff}");
            }
            else
            {
                Console.WriteLine("Success in UnmanagedProjectionConverter when using PROJ string.");
            }
        }
        catch (Exception)
        {
            Console.WriteLine($"Exception in creating UnmanagedProjectionConverter when using PROJ string.");
        }
    }
}

Check over 27700 National Grid source code:

internal class CheckOverBNG : CheckOverProjection
{
    protected override string TargetPROJ => "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy +units=m +no_defs";

    protected override int TargetEPSGCode => 27700;

    //Point in United Kingdom - Guildford (GLive)
    protected override PointShape PointInWGS => new PointShape(-0.5658779, 51.2382998);

    //Get it from EPSG.io
    protected override PointShape ExpectedProjectedPoint => new PointShape(500211.15180555126, 149768.161870003);
}

Check over LasVegas:

internal class CheckOverLasVegas : CheckOverProjection
{
    protected override string TargetPROJ => "+proj=tmerc +lat_0=36.25 +lon_0=-114.966666666667 +k=1.0001 +x_0=100000 +y_0=200000 +datum=NAD83 +units=m +no_defs";

    protected override int TargetEPSGCode => 8379;

    //Point in LasVegas - Best-Buy
    protected override PointShape PointInWGS => new PointShape(-115.1356839, 36.1197602);

    //Get it from EPSG.io
    protected override PointShape ExpectedProjectedPoint => new PointShape(500211.15180555126, 149768.161870003);
}

Hi Mahdi,

Attached is a new test program CheckThinkGeoProjection_09052024.zip (4.5 KB) with the following changes:

  1. The CheckOverLasVegas.ExpectedProjectedPoint was wrong, I got the right one from EPSG.IO and updated it.
  2. We updated the unmanaged projection to GdalProjectionConverter, which is recently added,

With the above changes, here below if the result

  1. The UnmanagedProjectionConverter in this updated version is using the latest Gdal 3.9.1, it should support all the latest epsgs.
  2. UnmanagedProjectionConverter still has issues when projecting the point in Britian, we have a clue and will fix that issue. We’ll keep you posted.
  3. It will take us longer to update the managed ProjectionConverter, I will recommend you to use the unmanaged one for now.

Thanks,
Ben

Hi Ben

I appreciate your assistance with resolving the EPSG:8379 issue. However, it seems that fixing that problem has caused another issue with EPSG:27700. Additionally, we are currently using version 12 and it appears that there is no GdalProjectionConverter in this version. Can you please confirm whether the issue with the ProjectionConverter for BNG EPSG:27700 persists even in the latest version of ThinkGeo?

Best wishes
Mahdi

Hi Mahdi,

  1. Does “caused another issue with EPSG:27700” means the following issue? If yes, We noticed 27700 worked with EPSG code in the old version, we have a clue and we should be able to fix that in the future version.

  2. GdalProjectionConverter only existed in the latest ThinkGeo.Gdal beta. The above 27700 issue does exist in the latest ThinkGeo package. In fact that’s the version I’m using in the CheckThinkGeoProjection_09052024.zip I sent over before.

So give us some time to dive in the 27700 issue, at the same time you can test if the 09052024 demo (which uses the latest proj and gdal) does support your other new EPSG numbers.

Thanks,
Ben

Hi Ben,

  1. Yes. As you can see, the difference in result is 120m.

Is there a way to incorporate the latest projection in version 12? Our product relies heavily on v12, Like using the ThinkGeo.Gdal beta version along with ThinkGeo.Core v12.

Best wishes
Mahdi

HI Mahdi,

I tested with the latest gdal, and found the reprojection from 4326->27700 is correct (the result is the same as EPSG.IO), while the result from 4326->27700 ProjString is 120 meters off for your 27700 test case, see below for the detail:

I updated the ThinkGeo code accordingly and now after updating to the latest ThinkGeo packages(ThinkGeo.Core beta039 and ThinkGeo.Gdal042), the Unmanaged GdalProjectionConverter works properly like following:


We will keep working on the Managed ProjectionConverter in the future.

Making it work on v12 is not that straightforward. Can you create a ticket or email sales@thinkgeo.com, letting us know your timeline, and we should then be able to give you some options how to proceed.

Thanks,
Ben