简体   繁体   English

如何在 C# 中使用 GMAP.NET 在 MAP 上绘制圆圈

[英]How to draw circle on the MAP using GMAP.NET in C#

I am using GMAP.NET in c#.我在 C# 中使用 GMAP.NET。 I am able to display the map on the form, now i am trying to draw a CIRCLE mouse by clicking on a certian point, keeping the left mouse button and dragging the mouse upto specific place.我能够在表单上显示地图,现在我试图通过单击某个特定点来绘制 CIRCLE 鼠标,按住鼠标左键并将鼠标拖动到特定位置。 Once the circle is drawn I want to get its radius in miles from the center point which I am sure GMAP is capable of doing it.一旦绘制了圆圈,我想从中心点获得它的半径(以英里为单位),我确信 GMAP 能够做到这一点。 I am using Opentstreet maps.我正在使用 Opentstreet 地图。

I am just unable to achive this functionly, anybody who has played with GMAP control kindly share your experience with some code which will work.我只是无法实现此功能,任何玩过 GMAP 控件的人都请与一些可以工作的代码分享您的经验。

Thanks谢谢

The only way that I am aware of that can achieve such a result is to create a list with PointLatLng points and draw them as a polygon.我知道可以实现这样的结果的唯一方法是创建一个包含 PointLatLng 点的列表并将它们绘制为多边形。 Here is an example:下面是一个例子:

private void CreateCircle(PointF point, double radius, int segments)
{

    List<PointLatLng> gpollist = new List<PointLatLng>();

    double seg = Math.PI * 2 / segments;

    for (int i = 0; i < segments; i++)
    {
        double theta = seg * i;
        double a = point.X + Math.Cos(theta) * radius;
        double b = point.Y + Math.Sin(theta) * radius;
    
        PointLatLng gpoi = new PointLatLng(a,b);

        gpollist.Add(gpoi);
     }
     GMapPolygon gpol = new GMapPolygon(gpollist, "pol");

     overlayOne.Polygons.Add(gpol);
 }

If you want to use the typical GDI features associated with the drawing class, you can simply inherit the GMapMarker class.如果要使用与绘图类关联的典型 GDI 功能,只需继承 GMapMarker 类即可。 This allows you to draw simple shapes, like circles, and create custom properties (for instance, one that will calculate the radius in miles of the shape):这允许您绘制简单的形状,如圆形,并创建自定义属性(例如,将计算以英里为单位的形状半径的属性):

public class GMapPoint : GMap.NET.WindowsForms.GMapMarker
{
    private PointLatLng point_;
    private float size_;
    public PointLatLng Point
    {
        get
        {
            return point_;
        }
        set
        {
            point_ = value;
        }
    }
    public GMapPoint(PointLatLng p, int size)
        : base(p)
    {
        point_ = p;
        size_ = size;
    }

    public override void OnRender(Graphics g)
    {
        g.FillRectangle(Brushes.Black, LocalPosition.X, LocalPosition.Y, size_, size_); 
        //OR 
        g.DrawEllipse(Pens.Black, LocalPosition.X, LocalPosition.Y, size_, size_);
        //OR whatever you need

    }
 }

To draw points on the map:要在地图上绘制点:

        GMapOverlay points_ = new GMapOverlay("pointCollection");
        points_.Markers.Add(new GMapPoint(new PointLatLng(35.06, -106.36), 10));

        gMapControl1.Overlays.Add(points_);

(And because I had some questions about it) Since we are inhereting from the markers class, we can still take advantage of the tooltiptext capability: (并且因为我对此有一些疑问)由于我们继承自标记类,我们仍然可以利用工具提示文本功能:

        GMapPoint pnt = new GMapPoint(new PointLatLng(35.06, -106.36), 10);
        pnt.Size = new Size(10,10);
        pnt.ToolTipText = "Text Here";
        pnt.ToolTipMode = MarkerTooltipMode.Always;
        points_.AddMarker(pnt);
   private void CreateCircle(Double lat, Double lon, double radius, int ColorIndex)
    {
        PointLatLng point = new PointLatLng(lat, lon);
        int segments = 1080;

        List<PointLatLng> gpollist = new List<PointLatLng>();

        for (int i = 0; i < segments; i++)
        {
            gpollist.Add(FindPointAtDistanceFrom(point, i*(Math.PI/180), radius / 1000));
        }

        GMapPolygon polygon = new GMapPolygon(gpollist, "Circle");
        switch (ColorIndex) {

            case 1:
                polygon.Fill = new SolidBrush(Color.FromArgb(80, Color.Red));
                break;
            case 2:
                polygon.Fill = new SolidBrush(Color.FromArgb(80, Color.Orange));
                break;
            case 3:
                polygon.Fill = new SolidBrush(Color.FromArgb(20, Color.Aqua));
                break;
            default:
                MessageBox.Show("No search zone found!");
                break;
        }


        polygon.Stroke = new Pen(Color.Red, 1);
        markers.Polygons.Add(polygon);
        gMapCtl.Overlays.Add(markers);
    }


    public static GMap.NET.PointLatLng FindPointAtDistanceFrom(GMap.NET.PointLatLng startPoint, double initialBearingRadians, double distanceKilometres)
    {
        const double radiusEarthKilometres = 6371.01;
        var distRatio = distanceKilometres / radiusEarthKilometres;
        var distRatioSine = Math.Sin(distRatio);
        var distRatioCosine = Math.Cos(distRatio);

        var startLatRad = DegreesToRadians(startPoint.Lat);
        var startLonRad = DegreesToRadians(startPoint.Lng);

        var startLatCos = Math.Cos(startLatRad);
        var startLatSin = Math.Sin(startLatRad);

        var endLatRads = Math.Asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.Cos(initialBearingRadians)));
        var endLonRads = startLonRad + Math.Atan2(Math.Sin(initialBearingRadians) * distRatioSine * startLatCos,distRatioCosine - startLatSin * Math.Sin(endLatRads));

        return new GMap.NET.PointLatLng(RadiansToDegrees(endLatRads), RadiansToDegrees(endLonRads));
    }

    public static double DegreesToRadians(double degrees)
    {
        const double degToRadFactor = Math.PI/180;
        return degrees * degToRadFactor;
    }

    public static double RadiansToDegrees(double radians)
    {
        const double radToDegFactor = 180/Math.PI;
        return radians * radToDegFactor;
    }



    public static double DistanceTwoPoint(double startLat, double startLong, double endLat, double endLong) {

        var startPoint = new GeoCoordinate(startLat, startLong);
        var endPoint = new GeoCoordinate(endLat, endLong);

        return startPoint.GetDistanceTo(endPoint);
    }

I hit the same problem and on entry I had Lon, Lat and radius, here is my solution.我遇到了同样的问题,进入时我有 Lon、Lat 和 radius,这是我的解决方案。 It works like a charm :)它就像一个魅力:)

private void CreateCircle(Double lat, Double lon, double radius)
{
   PointLatLng point = new PointLatLng(lat, lon);
   int segments = 1000;

   List<PointLatLng> gpollist = new List<PointLatLng>();

   for (int i = 0; i < segments; i++)
      gpollist.Add(FindPointAtDistanceFrom(point, i, radius / 1000));

   GMapPolygon gpol = new GMapPolygon(gpollist, "pol");

   markers.Polygons.Add(gpol);
}

public static GMap.NET.PointLatLng FindPointAtDistanceFrom(GMap.NET.PointLatLng startPoint, double initialBearingRadians, double distanceKilometres)
{
   const double radiusEarthKilometres = 6371.01;
   var distRatio = distanceKilometres / radiusEarthKilometres;
   var distRatioSine = Math.Sin(distRatio);
   var distRatioCosine = Math.Cos(distRatio);

   var startLatRad = DegreesToRadians(startPoint.Lat);
   var startLonRad = DegreesToRadians(startPoint.Lng);

   var startLatCos = Math.Cos(startLatRad);
   var startLatSin = Math.Sin(startLatRad);

   var endLatRads = Math.Asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.Cos(initialBearingRadians)));

   var endLonRads = startLonRad + Math.Atan2(
                 Math.Sin(initialBearingRadians) * distRatioSine * startLatCos,
                 distRatioCosine - startLatSin * Math.Sin(endLatRads));

   return new GMap.NET.PointLatLng(RadiansToDegrees(endLatRads), RadiansToDegrees(endLonRads));
}

public static double DegreesToRadians(double degrees)
{
  const double degToRadFactor = Math.PI / 180;
  return degrees * degToRadFactor;
}

public static double RadiansToDegrees(double radians)
{
  const double radToDegFactor = 180 / Math.PI;
  return radians * radToDegFactor;
}

call称呼

CreateCircle(51.640980, -2.673544, 1143.899431);
private void CreateCircle(PointF point, double radius, int segments)
{

List<PointLatLng> gpollist = new List<PointLatLng>();

double seg = Math.PI * 2 / segments;

int y = 0;
for (int i = 0; i < segments; i++)
{
    double theta = seg * i;
    double a = point.x + Math.cos( theta ) * radius;
    double b = point.y + Math.sin( theta ) * radius;

    PointLatLng gpoi = new PointLatLng(a,b);

    gpollist.Add(gpoi);
 }
 GMapPolygon gpol = new GMapPolygon(gpollist, "pol");

 overlayOne.Polygons.Add(gpol);
 }`enter code here`

so the apartment is not going ellipses所以公寓不会变成椭圆形

Here's how to draw a red circle, with black border on the map in WPF:以下是如何在 WPF 中绘制地图上带有黑色边框的红色圆圈:

public class YourMapControl : GMapControl
{
   protected override void OnRender(DrawingContext drawingContext)
   {
      base.OnRender(drawingContext);

      Point center(40.730610, -73.935242);
      double radius = 0.1;

      drawingContext.DrawEllipse(Brushes.Red, Pens.Black, center, radius, radius);
   }
}

As far as the second part of the question itself, you would use the following built-in MapControl functions:至于问题本身的第二部分,您将使用以下内置 MapControl 函数:

public bool DisableAltForSelection; //if true, selects area just by holding mouse and moving
public bool SelectionUseCircle; //use circle for selection
public event SelectionChange OnSelectionChange; //occurs when mouse selection is changed
public RectLatLng SelectedArea { get; set; } //returns rect with coordinates of the selected area
        GMapOverlay markers = new GMapOverlay("markers");
        private void CreateCircle(Double lat, Double lon, double radius, int segments)
        {
            markers.Polygons.Clear();
            PointLatLng point = new PointLatLng(lat, lon);

            List<PointLatLng> gpollist = new List<PointLatLng>();
            for (int i = 0; i < segments; i++)
                gpollist.Add(FindPointAtDistanceFrom(point, i, radius / 1000));

            List<PointLatLng> gpollistR = new List<PointLatLng>();
            List<PointLatLng> gpollistL = new List<PointLatLng>();
            foreach (var gp in gpollist)
            {
                if (gp.Lng > lon)
                {
                    gpollistR.Add(gp);
                }
                else
                {
                    gpollistL.Add(gp);
                }
            }
            gpollist.Clear();

            List<PointLatLng> gpollistRT = new List<PointLatLng>();
            List<PointLatLng> gpollistRB = new List<PointLatLng>();
            foreach (var gp in gpollistR)
            {
                if (gp.Lat > lat)
                {
                    gpollistRT.Add(gp);
                }
                else
                {
                    gpollistRB.Add(gp);
                }
            }
            gpollistRT.Sort(new LngComparer());
            gpollistRB.Sort(new Lng2Comparer());
            gpollistR.Clear();
            List<PointLatLng> gpollistLT = new List<PointLatLng>();
            List<PointLatLng> gpollistLB = new List<PointLatLng>();
            foreach (var gp in gpollistL)
            {
                if (gp.Lat > lat)
                {
                    gpollistLT.Add(gp);
                }
                else
                {
                    gpollistLB.Add(gp);
                }
            }
            //gpollistLT.Sort(new LngComparer());
            gpollistLB.Sort(new Lng2Comparer());
            gpollistLT.Sort(new LngComparer());
            gpollistL.Clear();


            gpollist.AddRange(gpollistRT);
            gpollist.AddRange(gpollistRB);
            gpollist.AddRange(gpollistLB);
            gpollist.AddRange(gpollistLT);
            GMapPolygon gpol = new GMapPolygon(gpollist, "pol");
            gpol.Stroke = new Pen(Color.Red, 1);
            markers.Polygons.Add(gpol);
        }

        public static GMap.NET.PointLatLng FindPointAtDistanceFrom(GMap.NET.PointLatLng startPoint, double initialBearingRadians, double distanceKilometres)
        {
            const double radiusEarthKilometres = 6371.01;
            var distRatio = distanceKilometres / radiusEarthKilometres;
            var distRatioSine = Math.Sin(distRatio);
            var distRatioCosine = Math.Cos(distRatio);

            var startLatRad = DegreesToRadians(startPoint.Lat);
            var startLonRad = DegreesToRadians(startPoint.Lng);

            var startLatCos = Math.Cos(startLatRad);
            var startLatSin = Math.Sin(startLatRad);

            var endLatRads = Math.Asin((startLatSin * distRatioCosine) + (startLatCos * distRatioSine * Math.Cos(initialBearingRadians)));

            var endLonRads = startLonRad + Math.Atan2(
                          Math.Sin(initialBearingRadians) * distRatioSine * startLatCos,
                          distRatioCosine - startLatSin * Math.Sin(endLatRads));

            return new GMap.NET.PointLatLng(RadiansToDegrees(endLatRads), RadiansToDegrees(endLonRads));
        }

        public static double DegreesToRadians(double degrees)
        {
            const double degToRadFactor = Math.PI / 180;
            return degrees * degToRadFactor;
        }

        public static double RadiansToDegrees(double radians)
        {
            const double radToDegFactor = 180 / Math.PI;
            return radians * radToDegFactor;
        }

and this class和这个班级

class LngComparer : IComparer<PointLatLng>
    {
        #region IComparer Members

        public int Compare(PointLatLng x, PointLatLng y)
        {
            if (x == null || y == null)
                throw new ArgumentException("At least one argument is null");
            if (x.Lng == y.Lng)
            {
                if (x.Lat > y.Lat)
                {
                    return 1;
                }
                else if (x.Lat < y.Lat)
                {
                    return -1;
                }
                else
                {
                    return 0;
                }
            }
            if (x.Lng < y.Lng) return -1;
            return 1;
        }

        #endregion
    }
    class Lng2Comparer : IComparer<PointLatLng>
    {
        #region IComparer Members

        public int Compare(PointLatLng x, PointLatLng y)
        {
            if (x == null || y == null)
                throw new ArgumentException("At least one argument is null");
            if (x.Lng == y.Lng)
            {
                if (x.Lat > y.Lat)
                {
                    return 1;
                }
                else if (x.Lat > y.Lat)
                {
                    return -1;
                }
                else
                {
                    return 0;
                }
            }
            if (x.Lng > y.Lng) return -1;
            return 1;
        }

        #endregion
    }

My code draws arcs and inherits from GMapMarker too.我的代码也绘制弧线并从 GMapMarker 继承。 The arc sweeps from point A to point B with the pivot point at C. Where point A and B are coincidental, a circle will be drawn.圆弧从 A 点扫到 B 点,轴心点在 C。在 A 点和 B 点重合的地方,将绘制一个圆。

    public class CustomArc : GMapMarker, ISerializable {
    [NonSerialized]
    public Pen pen;

    private int radius = 20;
    private int pen_width = 2;

    private float start = 0.0f;
    private float sweep = 0.0f;

    private GPoint ptA;
    private GPoint ptB;
    private GPoint ptC;
    private List<PointF> points;

    private static Logger logger = LogManager.GetCurrentClassLogger();

    public CustomArc(GPoint ptA, GPoint ptB, GPoint ptC, PointLatLng geo) : base(geo) {
        this.ptA = ptA;
        this.ptB = ptB;
        this.ptC = ptC;
        initialise();
    }

    private void initialise() {
        this.pen = new Pen(Brushes.White, this.pen_width);
        this.radius = (int)UIMaths.distance(ptC, ptA);

        this.points = new List<PointF>();

        if (ptA == ptB) {
            this.sweep = 360.0f;
        } else {
            // Calculate the radius
            this.sweep = (float)UIMaths.sweepAngleDeg(ptA, ptB, ptC);
        }
        this.start = (float)UIMaths.startAngle(ptC, ptB);
        Size = new Size(2 * radius, 2 * radius);
        Offset = new Point(-Size.Width / 2, -Size.Height / 2);

        Console.Out.WriteLine("Radius {0}, Start {1:0.0}, Sweep {2:0.0}", radius, start, sweep);
    }



    public override void OnRender(Graphics g) {
        try {
            Rectangle rect = new Rectangle(LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);
            g.DrawArc(pen, rect, start, sweep);

        } catch (ArgumentException ex) {
            logger.Error(ex.Message);
        }
    }

    public sealed override void Dispose() {
        if (pen != null) {
            pen.Dispose();
            pen = null;
        }

        base.Dispose();
    }

    #region ISerializable Members

    void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
        base.GetObjectData(info, context);
    }

    protected CustomArc(SerializationInfo info, StreamingContext context)
     : base(info, context) {
    }
    #endregion

}

My approach was to override paint event then define a rectangle.我的方法是覆盖绘画事件然后定义一个矩形。 Once you define a rectangle you can draw circle or arc or pie.定义矩形后,您可以绘制圆、弧或饼图。

private void MainMap_Paint(object sender, PaintEventArgs e)
{
   drawPie(e.Graphics, 50, 22.321, 45.44498);   
 }

private void drawPie(Graphics g, int angle, double latitude, double longitude)
{
    PointLatLng pn = new PointLatLng(latitude , longitude );
    double dist = 295; // 200 km
    // define rectangle points
    PointLatLng p1 = FindPointAtDistanceFrom(pn, 315 * constants.DEGREES_TO_RADIAN, dist);
    PointLatLng p2 = FindPointAtDistanceFrom(pn, 45 * constants.DEGREES_TO_RADIAN, dist);
    PointLatLng p3 = FindPointAtDistanceFrom(pn, 135 * constants.DEGREES_TO_RADIAN, dist);
    PointLatLng p4 = FindPointAtDistanceFrom(pn, 225 * constants.DEGREES_TO_RADIAN, dist);
    GPoint dp1 = MainMap.FromLatLngToLocal(p1);
    GPoint dp2 = MainMap.FromLatLngToLocal(p2);
    GPoint dp3 = MainMap.FromLatLngToLocal(p3);
    GPoint dp4 = MainMap.FromLatLngToLocal(p4);

    RectangleF rec = new RectangleF(dp1.X, dp1.Y, dp2.X - dp1.X, dp3.Y - dp1.Y);
    SolidBrush ptlbrush = new SolidBrush(Color.Cyan);
    Pen ptlpen = new Pen(ptlbrush, 1);                        
    float direction1 = (-90 + angle - 45) % 360;
    float startAngle = direction1;
    float sweepAngle = 90;                                                                
    
    var brush = new SolidBrush(Color.FromArgb(50, 80, 0, 150));
    g.DrawPie(ptlpen, rec, startAngle, sweepAngle);
    if (angleFilledBox.Checked == true)
        g.FillPie(brush, Rectangle.Round(rec), startAngle, sweepAngle);

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM