GMap.Net开发之技巧小结

来源:互联网 发布:java final修饰数组 编辑:程序博客网 时间:2024/05/16 05:47

转自:http://www.cnblogs.com/luxiaoxun/p/3530341.html

1、在GMap地图上,如果要让添加的图标(Marker)有个高亮(highlight)的效果,可以在MouseOver到Marker的时候设置Marker外观效果。

如果要让图标有个报警闪烁的效果,可以设置一个定时器,在定时器中改变Marker的外观,或者是用GDI来画圆闪动,带报警效果的Marker如下:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using GMap.NET;using GMap.NET.WindowsForms;using System.Drawing;using System.Windows.Forms;namespace GMapWinFormDemo{    class GMapMarkerImage : GMapMarker    {        private Image image;        public Image Image        {            get            {                return image;            }            set            {                image = value;                if (image != null)                {                    this.Size = new Size(image.Width, image.Height);                }            }        }        public bool IsHighlight = true;        public Pen HighlightPen { set; get; }        public Pen FlashPen { set; get; }        private Timer flashTimer = new Timer();        private int radius;        private int flashRadius;        public GMapMarkerImage(GMap.NET.PointLatLng p, Image image)            : base(p)        {            Size = new System.Drawing.Size(image.Width, image.Height);            Offset = new System.Drawing.Point(-Size.Width / 2, -Size.Height / 2);            Image = image;            HighlightPen = new System.Drawing.Pen(Brushes.Red,2);            radius = Size.Width >= Size.Height ? Size.Width : Size.Height;            flashTimer.Interval = 10;            flashTimer.Tick += new EventHandler(flashTimer_Tick);        }        public void StartFlash()        {            flashTimer.Start();        }        void flashTimer_Tick(object sender, EventArgs e)        {            if (FlashPen == null)            {                FlashPen = new Pen(Brushes.Red, 3);                flashRadius = radius;            }            else            {                flashRadius += radius/4;                if (flashRadius >= 2 * radius)                {                    flashRadius = radius;                    FlashPen.Color = Color.FromArgb(255, Color.Red);                }                else                {                    Random rand = new Random();                    int alpha = rand.Next(255);                    FlashPen.Color = Color.FromArgb(alpha, Color.Red);                }            }            this.Overlay.Control.Refresh();        }        public void StopFlash()        {            flashTimer.Stop();            if (FlashPen != null)            {                FlashPen.Dispose();                FlashPen = null;            }            this.Overlay.Control.Refresh();        }        public override void OnRender(Graphics g)        {            if (image == null)                return;            Rectangle rect = new Rectangle(LocalPosition.X, LocalPosition.Y, Size.Width, Size.Height);            g.DrawImage(image, rect);            if (IsMouseOver && IsHighlight)            {                g.DrawRectangle(HighlightPen,rect);            }            if (FlashPen != null)            {                g.DrawEllipse(FlashPen,                    new Rectangle(LocalPosition.X - flashRadius / 2 + Size.Width/2, LocalPosition.Y - flashRadius / 2+Size.Height/2, flashRadius, flashRadius));            }        }        public override void Dispose()        {            if (HighlightPen != null)            {                HighlightPen.Dispose();                HighlightPen = null;            }            if (FlashPen != null)            {                FlashPen.Dispose();                FlashPen = null;            }            base.Dispose();        }    }}
复制代码

2、可以旋转角度的Marker,比如可以将一个箭头图标旋转一定角度来指向一个轨迹路线,代码如下:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Drawing;using GMap.NET;using GMap.NET.WindowsForms;using GMapWinFormDemo.Properties;namespace GMapWinFormDemo{    class GMapMarkerDirection : GMapMarker    {        private float Ang;        private Image image;        public Image Image        {            get            {                return image;            }            set            {                image = value;                if (image != null)                {                    this.Size = new Size(image.Width, image.Height);                }            }        }        public GMapMarkerDirection(PointLatLng p, Image image, float angle)            : base(p)        {            Ang = angle;            Image = image;            Size = new System.Drawing.Size(image.Width, image.Height);            Offset = new System.Drawing.Point(-Size.Width / 2, -Size.Height / 2);        }        public override void OnRender(Graphics g)        {            g.DrawImageUnscaled(RotateImage(Image, Ang), LocalPosition.X, LocalPosition.Y);        }        //http://www.codeproject.com/KB/graphics/rotateimage.aspx        //Author : James T. Johnson        private static Bitmap RotateImage(Image image, float angle)        {            if (image == null)                throw new ArgumentNullException("image");            const double pi2 = Math.PI / 2.0;            // Why can't C# allow these to be const, or at least readonly            // *sigh*  I'm starting to talk like Christian Graus :omg:            double oldWidth = (double)image.Width;            double oldHeight = (double)image.Height;            // Convert degrees to radians            double theta = ((double)angle) * Math.PI / 180.0;            double locked_theta = theta;            // Ensure theta is now [0, 2pi)            while (locked_theta < 0.0)                locked_theta += 2 * Math.PI;            double newWidth, newHeight;            int nWidth, nHeight; // The newWidth/newHeight expressed as ints            #region Explaination of the calculations            /*             * The trig involved in calculating the new width and height             * is fairly simple; the hard part was remembering that when              * PI/2 <= theta <= PI and 3PI/2 <= theta < 2PI the width and              * height are switched.             *              * When you rotate a rectangle, r, the bounding box surrounding r             * contains for right-triangles of empty space.  Each of the              * triangles hypotenuse's are a known length, either the width or             * the height of r.  Because we know the length of the hypotenuse             * and we have a known angle of rotation, we can use the trig             * function identities to find the length of the other two sides.             *              * sine = opposite/hypotenuse             * cosine = adjacent/hypotenuse             *              * solving for the unknown we get             *              * opposite = sine * hypotenuse             * adjacent = cosine * hypotenuse             *              * Another interesting point about these triangles is that there             * are only two different triangles. The proof for which is easy             * to see, but its been too long since I've written a proof that             * I can't explain it well enough to want to publish it.               *              * Just trust me when I say the triangles formed by the lengths              * width are always the same (for a given theta) and the same              * goes for the height of r.             *              * Rather than associate the opposite/adjacent sides with the             * width and height of the original bitmap, I'll associate them             * based on their position.             *              * adjacent/oppositeTop will refer to the triangles making up the              * upper right and lower left corners             *              * adjacent/oppositeBottom will refer to the triangles making up              * the upper left and lower right corners             *              * The names are based on the right side corners, because thats              * where I did my work on paper (the right side).             *              * Now if you draw this out, you will see that the width of the              * bounding box is calculated by adding together adjacentTop and              * oppositeBottom while the height is calculate by adding              * together adjacentBottom and oppositeTop.             */            #endregion            double adjacentTop, oppositeTop;            double adjacentBottom, oppositeBottom;            // We need to calculate the sides of the triangles based            // on how much rotation is being done to the bitmap.            //   Refer to the first paragraph in the explaination above for             //   reasons why.            if ((locked_theta >= 0.0 && locked_theta < pi2) ||                (locked_theta >= Math.PI && locked_theta < (Math.PI + pi2)))            {                adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth;                oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth;                adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight;                oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight;            }            else            {                adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight;                oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight;                adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth;                oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth;            }            newWidth = adjacentTop + oppositeBottom;            newHeight = adjacentBottom + oppositeTop;            nWidth = (int)Math.Ceiling(newWidth);            nHeight = (int)Math.Ceiling(newHeight);            Bitmap rotatedBmp = new Bitmap(nWidth, nHeight);            using (Graphics g = Graphics.FromImage(rotatedBmp))            {                // This array will be used to pass in the three points that                 // make up the rotated image                Point[] points;                /*                 * The values of opposite/adjacentTop/Bottom are referring to                  * fixed locations instead of in relation to the                 * rotating image so I need to change which values are used                 * based on the how much the image is rotating.                 *                  * For each point, one of the coordinates will always be 0,                  * nWidth, or nHeight.  This because the Bitmap we are drawing on                 * is the bounding box for the rotated bitmap.  If both of the                  * corrdinates for any of the given points wasn't in the set above                 * then the bitmap we are drawing on WOULDN'T be the bounding box                 * as required.                 */                if (locked_theta >= 0.0 && locked_theta < pi2)                {                    points = new Point[] {                                              new Point( (int) oppositeBottom, 0 ),                                              new Point( nWidth, (int) oppositeTop ),                                             new Point( 0, (int) adjacentBottom )                                         };                }                else if (locked_theta >= pi2 && locked_theta < Math.PI)                {                    points = new Point[] {                                              new Point( nWidth, (int) oppositeTop ),                                             new Point( (int) adjacentTop, nHeight ),                                             new Point( (int) oppositeBottom, 0 )                                                                  };                }                else if (locked_theta >= Math.PI && locked_theta < (Math.PI + pi2))                {                    points = new Point[] {                                              new Point( (int) adjacentTop, nHeight ),                                              new Point( 0, (int) adjacentBottom ),                                             new Point( nWidth, (int) oppositeTop )                                         };                }                else                {                    points = new Point[] {                                              new Point( 0, (int) adjacentBottom ),                                              new Point( (int) oppositeBottom, 0 ),                                             new Point( (int) adjacentTop, nHeight )                                                 };                }                g.DrawImage(image, points);            }            return rotatedBmp;        }    }}
复制代码

3、在点击图标Marker的时候出现ContextMenuStrip:

复制代码
        void mapControl_OnMarkerClick(GMapMarker item, MouseEventArgs e)        {            if (e.Button == System.Windows.Forms.MouseButtons.Left)            {                this.contextMenuStrip1.Show(Cursor.Position);                if (item is GMapMarkerImage)                {                    currentMarker = item as GMapMarkerImage;                }            }        }
复制代码

4、随地图放大缩小的圆,代码来自官方Demo:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Drawing;using GMap.NET;using GMap.NET.WindowsForms;namespace GMapWinFormDemo{    public class GMapMarkerCircle : GMapMarker    {        /// <summary>        /// In Meters        /// </summary>        public int Radius;        /// <summary>        /// specifies how the outline is painted        /// </summary>        public Pen Stroke = new Pen(Color.FromArgb(155, Color.MidnightBlue));        /// <summary>        /// background color        /// </summary>        public Brush Fill = new SolidBrush(Color.FromArgb(155, Color.AliceBlue));        /// <summary>        /// is filled        /// </summary>        public bool IsFilled = true;        public GMapMarkerCircle(PointLatLng p)            : base(p)        {            Radius = 100; // 100m            IsHitTestVisible = false;        }        public override void OnRender(Graphics g)        {            int R = (int)((Radius) / Overlay.Control.MapProvider.Projection.GetGroundResolution((int)Overlay.Control.Zoom, Position.Lat)) * 2;            if (IsFilled)            {                g.FillEllipse(Fill, new System.Drawing.Rectangle(LocalPosition.X - R / 2, LocalPosition.Y - R / 2, R, R));            }            g.DrawEllipse(Stroke, new System.Drawing.Rectangle(LocalPosition.X - R / 2, LocalPosition.Y - R / 2, R, R));        }        public override void Dispose()        {            if (Stroke != null)            {                Stroke.Dispose();                Stroke = null;            }            if (Fill != null)            {                Fill.Dispose();                Fill = null;            }            base.Dispose();        }    }}
复制代码

关键就是如何在放大缩小时确定圆的半径大小,半径大小为:

int R = (int)((Radius) / Overlay.Control.MapProvider.Projection.GetGroundResolution((int)Overlay.Control.Zoom, Position.Lat)) * 2;

通过当前的缩放比例zoom和圆心的纬度来得到地图在此条件下分辨率(resolution),分辨率的大小为一个像素大小所代表的距离(单位为米)。

所以当我采用画多边形的方式在地图上画圆时,实际得到的圆在小半径和地球赤道附近下是个圆,但是在纬度较大的地方画的圆就变成了椭圆,代码如下:

复制代码
namespace GMapWinFormDemo{    public static class CirclePolygon    {        public static GMapPolygon CreateCircle(PointLatLng center, double radius, string name)        {            List<PointLatLng> pList = new List<PointLatLng>();            int segments = 100000;            double seg = 2 * Math.PI / segments;            for (int i = 0; i < segments; ++i)            {                double theta = i * seg;                double a = center.Lat + Math.Cos(theta) * radius;                double b = center.Lng + Math.Sin(theta) * radius;                pList.Add(new PointLatLng(a, b));            }            GMapPolygon circle = new GMapPolygon(pList, name);            circle.Stroke = new Pen(Brushes.Red, 1);            return circle;        }    }}
复制代码

5、保存地图为图片:

复制代码
        private void buttonSaveMap_Click(object sender, EventArgs e)        {            try            {                using (SaveFileDialog dialog = new SaveFileDialog())                {                    dialog.Filter = "PNG (*.png)|*.png";                    dialog.FileName = "GMap.NET image";                    Image image = this.mapControl.ToImage();                    if (image != null)                    {                        using (image)                        {                            if (dialog.ShowDialog() == DialogResult.OK)                            {                                string fileName = dialog.FileName;                                if (!fileName.EndsWith(".png", StringComparison.OrdinalIgnoreCase))                                {                                    fileName += ".png";                                }                                image.Save(fileName);                                MessageBox.Show("图片已保存: " + dialog.FileName, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);                            }                        }                    }                }            }            catch (Exception exception)            {                MessageBox.Show("图片保存失败: " + exception.Message, "GMap.NET", MessageBoxButtons.OK, MessageBoxIcon.Hand);            }        }
复制代码

 

参考:

https://greatmaps.codeplex.com/

 

作者:阿凡卢
出处:http://www.cnblogs.com/luxiaoxun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
0 0