ThinkGeo.com    |     Documentation    |     Premium Support

EllipseShape Innacuracy issues

Hi all,

I have produced a simplified example included below to show the behavior I am seeing in our application along with a picture showing the behavior. Essentially the tool I am working on needs to draw a circle given a point feature and a user defined radius. The test data I am using is a township grid where each of the grid squares is 6 miles by 6 miles. With the radius of the EllipseShape set to 3.0 and the units set to DistanceUnit.Mile I am seeing that that EllipseShape diameter is roughly 2/3 of the expected 6 miles as you can in the included image I clicked roughly in the center of the grid square. I have double checked our grid data for accuracy.

Any ideas on what might be causing this?

 private async void OnMapViewLoaded(object sender, RoutedEventArgs e)
 {
     MapView.MapUnit = GeographyUnit.Meter;

     OpenStreetMapOverlay osm = new OpenStreetMapOverlay();
     MapView.Overlays.Add(osm);

     LayerOverlay testOverlay = new LayerOverlay();
     MapView.Overlays.Add("test overlay", testOverlay);

     Add3DTestLayer(testOverlay);

     MapView.MapClick += MapView_MapClick;

     MapView.CurrentExtent = new RectangleShape(-12620874, 6871071, -12553663, 6825972);

     await _mapView.RefreshAsync();
 }

private async void MapView_MapClick(object sender, MapClickMapViewEventArgs e)
{

    AreaStyle areaStyle = AreaStyle.CreateSimpleAreaStyle(GeoColors.Transparent, GeoColors.Black, 1);



    InMemoryFeatureLayer clickLayer = new InMemoryFeatureLayer();
    clickLayer.Projection = new Projection(3857);
    LayerOverlay layerOverlay = new LayerOverlay();

    ZoomLevel selectionZoomLevel = clickLayer.ZoomLevelSet.ZoomLevel01;
    selectionZoomLevel.CustomStyles.Add(areaStyle);
    selectionZoomLevel.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

    clickLayer.InternalFeatures.Add(new Feature(new EllipseShape(e.WorldLocation, 3.0,   _mapView.MapUnit, DistanceUnit.Mile)));

    layerOverlay.Layers.Add(clickLayer);
    await _mapView.RefreshAsync(layerOverlay);
}

        private void Add3DTestLayer(LayerOverlay testOverlay)
        {
            var test3DLayer = new FileGeoDatabaseFeatureLayer("C:/ProgramData/{redacted name township grid data}.gdb")
            {
                FeatureSource =
                {
                    ProjectionConverter = new ProjectionConverter(4269, 3857)
                },
                ActiveLayer = "{REDACTED TOWNSHIP LAYER}"
            };

            // Add the layer to the overlay we created earlier.
            testOverlay.Layers.Add("3D Test Data", test3DLayer);

            // Create a pen that we will use below.
            AreaStyle style = new AreaStyle(GeoPens.DimGray, new GeoSolidBrush(new GeoColor(64, GeoColors.ForestGreen)));

            // Create an Area style on zoom level 1 and then apply it to all zoom levels up to 20.
            test3DLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Clear();
            test3DLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(style);
            test3DLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
        }

Hi Sean,

What you’re seeing is actually expected once Web Mercator and projections get involved:

Web Mercator (EPSG:3857) distorts distance and area
In EPSG:3857, coordinates are in “pseudo-meters,” and does not preserve true ground distance or area. So a circle created as “3 miles” in Web Mercator space will not correspond to a perfect 3-mile radius on the earth’s surface, especially as you move away from the equator.

How to create a more accurate 3-mile circle

  1. Pick a local projected CRS for your area that uses meters and is designed for distance/area work (e.g., the appropriate UTM or State Plane zone, something like EPSG:269xx / 326xx depending on location).
  2. Reproject the click point into that local CRS.
  3. Construct the circle in local meters (convert miles → meters).
  4. Reproject the resulting geometry back to 3857 just for drawing.

On the map it may look slightly non-circular because of the projection, but the geometry itself will represent a true 3-mile radius on the ground.

Here’s a sample helper showing the idea (replace localEpsg with the correct EPSG for your region):

// 1) Choose an appropriate local projected CRS for your area (example only).
//    Replace 26915 with the EPSG that matches your local UTM/State Plane zone.

int localEpsg = 26915;
var sphericalMercatorToLocal = new ProjectionConverter(3857, localEpsg);
sphericalMercatorToLocal.Open();

private Feature GetCircleFeature(PointShape centerInWebMercator, double radiusInMiles)
{
    // 2) Project the clicked point from Web Mercator (3857) to the local CRS.
    var centerInLocal = (PointShape)sphericalMercatorToLocal.ConvertToExternalProjection(centerInWebMercator);

    // 3) Convert miles to meters (local CRS uses meters).
    double radiusMeters = radiusInMiles * 1609.344;

    // 4) Build the circle in local coordinates (width/height in meters).
    var ellipseInLocal = new EllipseShape(centerInLocal, radiusMeters * 2, radiusMeters * 2);
    var featureInLocal = new Feature(ellipseInLocal);

    // 5) Project the circle back to Web Mercator for display.
    var featureInWebMercator = sphericalMercatorToLocal.ConvertToInternalProjection(featureInLocal);

    return featureInWebMercator;
}

In your click handler you’d use this instead of constructing the EllipseShape directly in 3857

If you can’t use a local UTM projection, you can instead work in decimal degrees (EPSG:4326) and rely on geodesic (Haversine / great-circle) distance calculations. This won’t be as accurate as a good local projected CRS, but it’s usually acceptable if you don’t need survey-grade precision.

Thanks,
Ben

Excellent, Works great.

I figured I must be missing something projection related but wasn’t sure what.

Thanks!
Sean

That’s Awesome! :+1: