Draw ellipse based on Kilometer to Map.

Topics: Algorithms
May 25, 2011 at 12:55 PM

Hi!

I need to draw an elllipse to the map. The center Point of the ellipse is given but the radius is defined in kilometers. i also need to capture objects within the radius. do i have to convert from kilometers to pixel?  Any help is greatly appreciated.  Thanks in advance.

Aris.

May 26, 2011 at 2:18 AM

first you need some class that creates your geometries e.g.

 

public static class ShapeFactory
{
public static SharpMap.Geometries.LinearRing CreateRectangle(SharpMap.Geometries.Point leftTop, SharpMap.Geometries.Point rightBottom)
{
    var pts = new[]
                    {
                        leftTop, 
                        new Point(rightBottom.X, leftTop.Y), 
                        rightBottom,
                        new Point(leftTop.X, rightBottom.Y), 
                        leftTop
                    };
    return new LinearRing(pts);
}

public static SharpMap.Geometries.LinearRing CreateRectangle(SharpMap.Geometries.Point center, System.Drawing.SizeF size)
{
    var wh = new System.Drawing.SizeF(size.Width*0.5f, size.Height*0.5f);
    var lt = new SharpMap.Geometries.Point(center.X - wh.Width, center.Y + wh.Height);
    var rb = new SharpMap.Geometries.Point(center.X + wh.Width, center.Y - wh.Height);

    return CreateRectangle(lt, rb);
}

public static SharpMap.Geometries.LinearRing CreateEllipse(SharpMap.Geometries.Point center, System.Drawing.SizeF size)
{
    return CreateEllipse(center, size, 12);
}
        
public static SharpMap.Geometries.LinearRing CreateEllipse(SharpMap.Geometries.Point center, 
                                                            System.Drawing.SizeF size, 
                                                            int segmentsPerQuadrant)
{
    const double piHalf = System.Math.PI*0.5d;

    var step = piHalf/segmentsPerQuadrant;

    var pts = new SharpMap.Geometries.Point[4*segmentsPerQuadrant + 1];
    var angle = 0d;
    for (var i = 0; i < 4*segmentsPerQuadrant; i++)
    {
        pts[i] = new Point(center.X + Math.Cos(angle) * size.Width, 
                            center.Y + Math.Sin(angle) * size.Height);
        angle += step;
    }
    pts[pts.Length - 1] = pts[0];
    return new SharpMap.Geometries.LinearRing(pts);
}
}

Then you need to setup some SharpMap.Layer.VectorLayer with a SharpMap.Data.Providers.GeometryProvider as datasource:

var map = new SharpMap.Map(new Size(500, 500));
var gp = new SharpMap.Data.Providers.GeometryProvider(
    new SharpMap.Geometries.Geometry[]
        {
            new SharpMap.Geometries.Polygon(ShapeFactory.CreateEllipse(new Point(0, 0), new SizeF(40, 30))),
            ShapeFactory.CreateEllipse(new Point(90, 55), new SizeF(40, 30)),
            ShapeFactory.CreateEllipse(new Point(77, 24), new SizeF(40, 30)),
            ShapeFactory.CreateEllipse(new Point(-80, 41), new SizeF(40, 30)),
            ShapeFactory.CreateEllipse(new Point(-45, -36), new SizeF(40, 30)),
        });
var gl = new SharpMap.Layers.VectorLayer("GeometryLayer", gp);
map.Layers.Add(gl);
map.ZoomToExtents();
var mapimage = map.GetMap();
mapimage.Save("ellipse.png", ImageFormat.Png);
To calculate the radius you have to convert you center in metric projection, create you eclispe and after reproject in your first projection.
May 26, 2011 at 2:38 AM

Hi longuard,

   Thank you for your reply, i found this solution seems working but im still determining its accuracy. heres the code for those interested.

    //Snippet Written by Chris Pietschmann (http://pietschsoft.com)
    public static double ToRadian(double degrees)
    {
        return degrees * (Math.PI / 180);
    }

    public static double ToDegrees(double radians)
    {
        return radians * (180 / Math.PI);
    }
    //Create Cirle
    //Where Center is in form of Longtitude and Latitude
   //Radius is in Kilometers
    public static SharpMap.Geometries.LinearRing CreateCircle(Point center, double radius)
    {
        var earthRadius = 6367.0;
        var lng = ToRadian(center.X); //radians
        var lat = ToRadian(center.Y); //radians
        var d = radius / earthRadius; // d = angular distance covered on earth's surface
        var locations = new List<Point>();

        for (var x = 0; x <= 360; x++)
        {
            var brng = ToRadian(x);
            var latRadians = Math.Asin(Math.Sin(lat) * Math.Cos(d) + Math.Cos(lat) * Math.Sin(d) * Math.Cos(brng));
            var lngRadians = lng + Math.Atan2(Math.Sin(brng) * Math.Sin(d) * Math.Cos(lat), Math.Cos(d) - Math.Sin(lat) * Math.Sin(latRadians));
            locations.Add(new Point(ToDegrees(lngRadians),ToDegrees(latRadians)));
        }
        return new SharpMap.Geometries.LinearRing(locations);
    }