Как нарисовать круг на КАРТЕ с помощью GMAP.NET на C #

Я использую GMAP.NET на C #. Я могу отобразить карту в форме, теперь я пытаюсь нарисовать круговую мышь, щелкнув определенную точку, удерживая левую кнопку мыши и перетащив мышь в определенное место. После того, как круг нарисован, я хочу получить его радиус в милях от центральной точки, и я уверен, что GMAP может это сделать. Я использую карты Opentstreet.

Я просто не могу добиться этого функционально, любой, кто играл с контролем GMAP, любезно поделится своим опытом с некоторым кодом, который будет работать.

Спасибо


person Shax    schedule 16.02.2012    source источник


Ответы (8)


Единственный известный мне способ добиться такого результата - это создать список с точками PointLatLng и нарисовать их в виде многоугольника. Вот пример:

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);
 }
person elasticrash    schedule 20.03.2012
comment
Хороший код, спасибо. Незначительная настройка: Math.Cos и Math.Sin, заглавные буквы и радиус должны быть ОЧЕНЬ крошечными, например, 0,01, если вы отображаете масштаб в милю или два. - person TonyG; 04.03.2014

Если вы хотите использовать типичные функции GDI, связанные с классом рисования, вы можете просто унаследовать класс GMapMarker. Это позволяет рисовать простые формы, такие как круги, и создавать настраиваемые свойства (например, тот, который будет вычислять радиус формы в милях):

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

    }
 }

Чтобы нарисовать точки на карте:

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

        gMapControl1.Overlays.Add(points_);

(И потому что у меня есть несколько вопросов по этому поводу) Поскольку мы унаследованы от класса markers, мы все еще можем воспользоваться возможностью всплывающего текста:

        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);
person T James    schedule 08.12.2015
comment
@JAlecksen, Могу я узнать, как сделать то же самое с WPF? - person ; 10.05.2017
comment
@Manish Jain К сожалению, у меня не было опыта работы с WPF и Gmap. Когда-нибудь мне придется перейти, но я не с нетерпением жду такого обучения: P - person T James; 10.05.2017
comment
Спасибо за этот фрагмент кода. Я преобразовал его в VB.NET, и он отлично работал. Мне было интересно, поскольку мы рисуем точку на оверлее, как эти точки могут стать маркерами с всплывающими подсказками? - person The Newbie; 04.01.2019
comment
@TheNewbie Рад, что это помогло. Поскольку вы наследуете класс маркеров, вы должны иметь возможность добавлять всплывающие подсказки так же, как вы делаете это для любых других маркеров. - person T James; 04.01.2019
comment
Вот как я создаю маркер Dim marker As GMarkerGoogle = New GMarkerGoogle (New PointLatLng (lat, lng), GMarkerGoogleType.green). Эта маркерная переменная имеет функцию всплывающей подсказки, тогда как новый класс, который вы написали, не имеет функции всплывающей подсказки. Я не совсем уверен, как назначить всплывающую подсказку для маркеров, созданных вашим классом - person The Newbie; 04.01.2019
comment
Кстати, рисование маркера на карте вместо использования по умолчанию намного быстрее. Карта не так сильно лагает! - person The Newbie; 04.01.2019
comment
@TheNewbie Да, рисование растровых изображений занимает значительно больше времени, чем необработанные функции рисования. Предполагая, что вы используете приведенный выше пример кода, вы сможете добавить всплывающие подсказки в GMapPoint, например: GMapPoint p = new…; p.ToolTipMode = MarkerTooltipMode.Always; и m.ToolTipText = Текст; чем добавить его на слой: points_.AddMarker (p); Я протестировал это, и, похоже, он работает нормально. Надеюсь это поможет - person T James; 04.01.2019
comment
Спасибо, кажется, работает отлично, если для ToolTipMode установлено значение always, однако это скрывает всплывающие подсказки друг друга, если широта и долгота находятся рядом друг с другом. Может ли он также сохранить возможность показывать всплывающую подсказку только при наведении курсора? Я уже пробовал установить для ToolTipMode значение OnMouseOver, но не думаю, что это решено. Еще раз, спасибо! - person The Newbie; 04.01.2019
comment
@TheNewbie Вы пробовали использовать вместо этого MarkerTooltipMode.OnMouseOver? - person T James; 04.01.2019
comment
Ага, я сделал это. Кажется, не видно, когда я нахожу на него курсор. - person The Newbie; 04.01.2019
comment
Вот как я создаю новый слой и маркер и добавляю его на свою карту. Dim marker As GMapPoint marker = New GMapPoint(New PointLatLng(lat, lng), 15) marker.ToolTip = New GMapToolTip(marker) marker.ToolTipMode = MarkerTooltipMode.OnMouseOver marker.ToolTipText = "test" - person The Newbie; 04.01.2019
comment
@TheNewbie Итак, похоже, OnMouseOver использует размер маркера, чтобы определить, находится ли курсор над маркером или нет. Если вы используете мой класс как есть, вы никогда не устанавливаете известный размер в классе маркера. В дополнение к тому, что у вас есть, вам нужно будет сделать что-то вроде этого: pnt.Size = new Size (10, 10); или как вы хотите, чтобы была ваша толерантность к зависанию. - person T James; 04.01.2019
comment
Это работает как шарм. Ты рок человек. Также, если вы не возражаете, похоже, вы уже использовали это раньше, есть ли у вас какие-нибудь советы / рекомендации, чтобы еще больше оживить Gmap? Или вы просто просматриваете исходный код Gmaps и понимаете это таким образом? Тем не менее, мы, новички, благодарим таких, как вы, за помощь. Хорошего дня! - person The Newbie; 04.01.2019
comment
@TheNewbie Я просто просматриваю исходный код, чтобы увидеть, как он работает. Я новичок во многих темах и всегда использую этот сайт, чтобы получить помощь. Я счастлив отдать как можно больше! Удачного дня! - person T James; 04.01.2019

Я столкнулся с той же проблемой, и при входе у меня были Lon, Lat и radius, вот мое решение. Работает как часы :)

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;
}

вызов

CreateCircle(51.640980, -2.673544, 1143.899431);
person Andrzej Koloszewski    schedule 08.09.2016
comment
Спасибо ! С небольшими изменениями я могу сделать то же самое в wpf - person ; 11.05.2017

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`

так квартира не собирается эллипсами

person user5232224    schedule 16.08.2015

Вот как нарисовать красный круг с черной рамкой на карте в 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);
   }
}

Что касается второй части вопроса, вы должны использовать следующие встроенные функции 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
person Eternal21    schedule 02.06.2017

        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;
        }

и этот класс

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
    }
person porya ras    schedule 11.01.2019

Мой код рисует дуги и тоже наследуется от GMapMarker. Дуга проходит от точки 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

}
person Tony Dixon    schedule 14.02.2020

Мой подход заключался в том, чтобы переопределить событие рисования, а затем определить прямоугольник. Определив прямоугольник, вы можете нарисовать круг, дугу или круговую диаграмму.

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);

}
person Mohsen    schedule 21.02.2021