C#.Net Solution using GDAL/OGR bindings..
If you're willing to add the GDAL/OGR C# bindings to your .Net project (see second heading), then you can do what you want within a .Net environment. It's the same thing I did above in my prior answer using JavaScript, but 100% in C# here, and only one library— the GDAL C# bindings.
One (major) improvement of this implementation over my JavaScript example, is this version takes Well Known Text geometries, which can be point, line, polygon, multipart, etc., and buffers them without your having to additionally explode the individual coordinates then reassemble the geometries. So this is a huge improvement.
Like my JavaScript approach above, though, this route still applies the concept of using an Azimuthal Equidistant Projection centered on the geometry, then buffers on the localized grid, then transforms the geometry back to geographic coordinates. The projection is re-centered for every geometry submitted.
I drew from this GDAL C# example as a reference. Other GDAL C# examples are here.
using System;
using OSGeo.OSR;
using OSGeo.OGR;
namespace SharpGEO
{
class GeoUTIL
{
public static string BufferGeom(string wkt)
{
string projected_geom_WKT = "";
// If GDAL > 3.0..
// Unexpected coordinate reversal in Well Known Text!
// Explaination: https://github.com/OSGeo/gdal/issues/1546
// Solution is..
// SpatialReference.SetAxisMappingStrategy(AxisMappingStrategy.OAMS_TRADITIONAL_GIS_ORDER);
SpatialReference sr1 = new SpatialReference("");
sr1.ImportFromEPSG(4326);
sr1.SetAxisMappingStrategy(AxisMappingStrategy.OAMS_TRADITIONAL_GIS_ORDER);
Geometry g1 = Geometry.CreateFromWkt(wkt);
g1.AssignSpatialReference(sr1);
// Create localized Azimuthal Equidistant Projection centered on the point you want to buffer..
// Example:
// "+proj=aeqd +lon_0=-80.9957 +lat_0=33.97105 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=ft +no_defs";
// This block uniquely adapts the Azimuthal Equidistant Projection for every geometry submitted.
// We get the centroid in case a linestring or a polygon is submitted.
// This keeps the projection centered even for non-point shapes.
Geometry proj_center_geom = g1.Centroid();
string aeqd_proj_string = "+proj=aeqd +lon_0=" + proj_center_geom.GetX(0).ToString() +
" +lat_0=" + proj_center_geom.GetY(0).ToString() +
" +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=ft +no_defs";
// Transform to localized projection..
SpatialReference sr2 = new SpatialReference("");
sr2.ImportFromProj4(aeqd_proj_string);
sr2.SetAxisMappingStrategy(AxisMappingStrategy.OAMS_TRADITIONAL_GIS_ORDER);
g1.TransformTo(sr2);
// Buffer..
// https://gdal.org/python/osgeo.ogr.Geometry-class.html#Buffer
// 50 = distance in projection units (feet, in this case), and 30 = "quadsecs"
// "QuadSecs" are the number of segments used to represent 90-degree arc of circle..
Geometry g2 = g1.Buffer(50, 30);
g2.AssignSpatialReference(sr2); // We have to tell OGR the projection of the new geom
string g2WKT = "";
g2.ExportToWkt(out g2WKT);
Console.WriteLine(g2WKT);
// Transform back to WGS84/LatLng
g2.TransformTo(sr1);
string g2GeogWKT = "";
g2.ExportToWkt(out g2GeogWKT);
//Console.WriteLine(g2GeogWKT);
projected_geom_WKT = g2GeogWKT;
return projected_geom_WKT;
}
}
class Program
{
static void Main(string[] args)
{
// Point you want to buffer..
string latlngWKT = "POINT(-80.9957 33.97105)";
string proj_geom_WKT = GeoUTIL.BufferGeom(latlngWKT);
Console.WriteLine("-------------------------------");
Console.WriteLine(proj_geom_WKT);
}
}
}
I had to import the following GDAL/OGR assemblies (.dll files) into my C# project to reference the bindings:
gdal_csharp.dll
ogr_csharp.dll
osr_csharp.dll
I found them where I initially unpacked files for my GDAL installation in the following directory:
\bin\gdal\csharp
I also found them here (probably where GDAL copied them during install):
C:\Program Files (x86)\GDAL\csharp
One last thing, I ran into some build issues at first, and I had to go to Project > Properties > Build (tab), and set "Platform Target" to "x86".
A comment on that ..I probably intentionally installed 32-bit GDAL for macro compatibility with a lot of other things. But for this purpose, it might make sense to download a specific GDAL, like a 64-bit build, for importing into your project.
select st_buffer(st_geomfromtext('point (27 40)')::geography,10)::geometry
.