Been fighting this for almost a week now, so I'm hoping that someone here has some insight or can tell me the obvious thing I'm missing. I am trying to add programmatic coordinate conversion on the end of one of the products I've developed in C#. My boss recommended using ProjNET, so I got it from NuGet and implemented the code without much trouble.
At the testing stage, however, things broke. Through trial and error, I found that my results were perfect if the client stayed within the same datum, but any cross-datum conversions were incorrect. Our use case is primarily cross-datum conversions.
I did a bunch of searching and found that ProjNET requires both the source coordinate system and target coordinate system to include the ToWGS84 parameter: https://github.com/NetTopologySuite/ProjNet4GeoAPI/wiki/Projecting-points-from-one-coordinate-system-to-another
Ironically (and tragically), the ProjNET.SRID library on NuGet, which translates SRIDs into WKTs, does not provide the ToWGS84 parameter in their WKTs. My boss and I found another source to translate SRIDs that includes the ToWGS84 parameter, but the results are still incorrect, possibly because the source is old and the WKTs might be outdated.
Here's the core of the code that's giving me trouble, using Nevada West NAD27 and Nevada West NAD83, both in US Survey feet:
ProjNet.CoordinateSystems.CoordinateSystemFactory csFactory = new CoordinateSystemFactory();
ProjNet.CoordinateSystems.CoordinateSystem sourceCoordSys = csFactory.CreateFromWkt("PROJCS[\"NAD27 / Nevada West\", GEOGCS[\"NAD27\", DATUM[\"North American Datum 1927\", SPHEROID[\"Clarke 1866\", 6378206.4, 294.9786982138982, AUTHORITY[\"EPSG\",\"7008\"]], TOWGS84[-4.2, 135.4, 181.9, 0.0, 0.0, 0.0, 0.0], AUTHORITY[\"EPSG\",\"6267\"]], PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.017453292519943295], AXIS[\"Geodetic longitude\", EAST], AXIS[\"Geodetic latitude\", NORTH], AUTHORITY[\"EPSG\",\"4267\"]], PROJECTION[\"Transverse Mercator\"], PARAMETER[\"central_meridian\", -118.58333333333333], PARAMETER[\"latitude_of_origin\", 34.75], PARAMETER[\"scale_factor\", 0.9999], PARAMETER[\"false_easting\", 500000.0], PARAMETER[\"false_northing\", 0.0], UNIT[\"foot_survey_us\", 0.30480060960121924], AXIS[\"Easting\", EAST], AXIS[\"Northing\", NORTH], AUTHORITY[\"EPSG\",\"32009\"]]");
ProjNet.CoordinateSystems.CoordinateSystem targetCoordSys = csFactory.CreateFromWkt("PROJCS[\"NAD83 / Nevada West (ft US)\", GEOGCS[\"NAD83\", DATUM[\"North American Datum 1983\", SPHEROID[\"GRS 1980\", 6378137.0, 298.257222101, AUTHORITY[\"EPSG\",\"7019\"]], TOWGS84[1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0], AUTHORITY[\"EPSG\",\"6269\"]], PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], UNIT[\"degree\", 0.017453292519943295], AXIS[\"Geodetic longitude\", EAST], AXIS[\"Geodetic latitude\", NORTH], AUTHORITY[\"EPSG\",\"4269\"]], PROJECTION[\"Transverse Mercator\"], PARAMETER[\"central_meridian\", -118.58333333333333], PARAMETER[\"latitude_of_origin\", 34.75], PARAMETER[\"scale_factor\", 0.9999], PARAMETER[\"false_easting\", 2624666.6667], PARAMETER[\"false_northing\", 13123333.3333], UNIT[\"foot_survey_us\", 0.30480060960121924], AXIS[\"Easting\", EAST], AXIS[\"Northing\", NORTH], AUTHORITY[\"EPSG\",\"3423\"]]");
CoordinateTransformationFactory transformFactory = new CoordinateTransformationFactory();
ICoordinateTransformation coordTransform = transformFactory.CreateFromCoordinateSystems(sourceCoordSys, targetCoordSys);
double XTransfer, YTransfer;
<For Loop that iterates through resultTable>
{
(XTransfer, YTransfer) = coordTransform.MathTransform.Transform(
(double)resultTable.Rows[i][eastingColName],
(double)resultTable.Rows[i][northingColName]);
resultTable.Rows[i][eastingColName] = XTransfer;
resultTable.Rows[i][northingColName] = YTransfer;
}
And here's one of the test points I've been trying to correct:
Source SRID = 32009
Easting = 214491.354
Northing = 679690.231
And the results for target SRID = 3423:
From https://mygeodata.cloud/cs2cs/
Easting = 2338881.88508
Northing = 13803025.9945
From my code:
Easting = 2338932.15719927, difference of 50.272 US Survey feet
Northing = 13803002.2532437, difference of -23.741 US Survey feet
As an aside, we are not devoted to ProjNET, so I tried implementing the above in DotSpatial. I had the exact same experience of breaking down in cross-datum transformations. They have the solution to use grid shift files, but those didn't appear to have any effect once loaded. If anyone has insight into those, I'll gladly take it.
This is a similar question to here, but I cannot comment there due to the newness of my account, I obviously do not have an answer, and even the official strings from EPSG (recommended in a comment) do not contain the ToWGS84 parameter.