Getting the correct circle radius

May 24, 2012 at 11:27 AM

Hi,

I create an ellipse using the same code as in the MiElipse discussion I found on here. However, the radius distance is wrong.

I start off with a map coordinate in WGS84 representing the center of the circle and a radius value in meters. I transform the center point using the Wgs84toGoogleMercator MathTransform. The circle draws in the correct place but the radius is far too small.

How do I project the radius value?

Developer
May 25, 2012 at 2:23 AM
Edited May 25, 2012 at 3:10 AM

You try convert radius to miles:

radius=(radius/1609.344) ;// Convert meter to miles.

Example:

 /// <summary>
        /// Create circle by center in (latitude,longitude) and radius in meter
        /// </summary>
        /// <param name="point"> point with cordinator in lat,lng</param>
        /// <param name="radius">radius in meter</param>
        /// <returns>Circle with center is point and radius above</returns>
        public static SharpMap.Geometries.LinearRing CreateCircle(SharpMap.Geometries.Point point, double radius)
        {
            SharpMap.Geometries.LinearRing result =null;
            radius  = radius/1609.344; // Convert metters to miles             
                    
            var d2r = Math.PI/180;
            //var r2d = 180/Math.PI;
            var Clat = radius * 0.014483;  // Convert miles into degrees latitude
            var Clng = Clat/Math.Cos(point.X*d2r);
            var Cpoints = new Collection<SharpMap.Geometries.Point>();
            for (var i=0; i < 33; i++) { 
                var theta = Math.PI * (i/16);
                var Cy = point.X + (Clat * Math.Sin(theta));
                var Cx = point.Y + (Clng * Math.Cos(theta));
                var P = new SharpMap.Geometries.Point(Cy, Cx);
                    Cpoints.Add(P);
            }
            result = new LinearRing(Cpoints);
            return result;
        }

May 25, 2012 at 11:30 AM

Hi Trieuvy,

The CreateCircle code didnt work. It gives me an OutOfMemoryException when I try to draw the resulting polygon at the line:

PathGradientBrush pthGrBrush = new PathGradientBrush(path);

I modified my existing circle creation method to multiply the radius by 1.609344 but its still not quite correct.

Why is there a need to convert the radius from metres to miles? How do I know if my map projection is using metres or miles?

Here is the code I use to generate the circle:

    public static NetTopologySuite.Geometries.Polygon CreateEllipse(NetTopologySuite.Geometries.Point center,
                                                        double radius,
                                                        int segmentsPerQuadrant)
    {
      const double piHalf = System.Math.PI * 0.5d;

      double step = piHalf / segmentsPerQuadrant;

      radius = radius * 1.609344; // Convert metters to miles      

      System.Collections.ObjectModel.Collection pts =
          new System.Collections.ObjectModel.Collection();

      double angle = 0d;
      for (int i = 0; i < 4 * segmentsPerQuadrant; i++)
      {
        NetTopologySuite.Geometries.Point pt = new NetTopologySuite.Geometries.Point(
                                                                (int)(center.X + Math.Cos(angle) * radius),
                                                                (int)(center.Y + Math.Sin(angle) * radius)
                                                                );

        pts.Add( pt.Coordinate );
        angle += step;
      }
      pts[pts.Count - 1] = pts[0];

      LinearRing lr = new NetTopologySuite.Geometries.LinearRing(pts.ToArray());
      Polygon poly = new Polygon(lr);
      return poly;
    }

Developer
May 28, 2012 at 5:03 AM
Edited May 28, 2012 at 5:52 AM

If you use Wgs84toGoogleMercator. You have to convert radius to Mercator.

Sorry my function use on web for point is ( latitude, longitude). Coordinates ( points ) is opposite in sharpmap: ( longitude, latitude)

Try swap latitude and longitude follow (Note: I have not test it on Sharpmap)

 

/// <summary>
        /// Create circle by center in (latitude,longitude) and radius in meter
        /// </summary>
        /// <param name="point"> point with cordinator in lat,lng</param>
        /// <param name="radius">radius in meter</param>
        /// <returns>Circle with center is point and radius above</returns>
        public static SharpMap.Geometries.LinearRing CreateCircle(SharpMap.Geometries.Point point, double radius)
        {
            SharpMap.Geometries.LinearRing result =null;
            radius  = radius/1609.344; // Convert metters to miles             
                    
            var d2r = Math.PI/180;
            //var r2d = 180/Math.PI;
            var Clat = radius * 0.014483;  // Convert miles into degrees latitude
            var Clng = Clat/Math.Cos(point.Y*d2r);
            var Cpoints = new Collection<SharpMap.Geometries.Point>();
            for (var i=0; i < 33; i++) { 
                var theta = Math.PI * (i/16);
                var Cy = point.Y + (Clat * Math.Sin(theta));
                var Cx = point.X + (Clng * Math.Cos(theta));
                var P = new SharpMap.Geometries.Point(Cx, Cy);
                Cpoints.Add(P);
            }
            result = new LinearRing(Cpoints);
            return result;
        }

In your function. You can try to change follow

 public static NetTopologySuite.Geometries.Polygon CreateEllipse(NetTopologySuite.Geometries.Point center,
                                                        double radius,
                                                        int segmentsPerQuadrant)
    {
      const double piHalf = System.Math.PI * 0.5d;

      double step = piHalf / segmentsPerQuadrant;

      
radius =  radius/1609.344; // Convert metters to miles

var radius_y=radius*0.014483; // Convert miles into degrees latitude
var radius_x=radius_y/Math.Cos(center.Y*Math.PI/180); // Convert miles into degrees longitude

      System.Collections.ObjectModel.Collection pts =
          new System.Collections.ObjectModel.Collection();

      double angle = 0d;
      for (int i = 0; i < 4 * segmentsPerQuadrant; i++)
      {
        NetTopologySuite.Geometries.Point pt = new NetTopologySuite.Geometries.Point(
                                                                (int)(center.X + Math.Cos(angle) * radius_x),
                                                                (int)(center.Y + Math.Sin(angle) * radius_y)
                                                                );

        pts.Add( pt.Coordinate );
        angle += step;
      }
      pts[pts.Count - 1] = pts[0];

      LinearRing lr = new NetTopologySuite.Geometries.LinearRing(pts.ToArray());
      Polygon poly = new Polygon(lr);
      return poly;
    }

:

 

 

 

radius 
May 30, 2012 at 9:05 AM

Hi trieuvy,

Thanks but unfortunately that still doesnt work. It produces a very small circle.

Please try the following using SharpMap:

* Use Google Satellite view as the tile source for the background layer.

* Create a PolygonalVectorLayer containing 1 ellipse polygon. Give it a radius of 100.

* When the map is drawn with the ellipse on it open Google Earth and go to the same location. Use the ruler tool to check how far the radius should extend.

Developer
May 30, 2012 at 10:14 AM

My function run ok on google map by google map API.

- Review radius is meters.

- Review your point is: (longitude, latitude) ( wgs84 srid:4326).

- I dont know Why do you change double to (int) in follow code:

NetTopologySuite.Geometries.Point( (int)(center.X + Math.Cos(angle) * radius_x), (int)(center.Y + Math.Sin(angle) * radius_y) );