GMap 自定义绘图
GMap自定义绘图
gmap自带的绘图只难绘制路径,多边形,固定大小的圆.在实际开发中可能这些并不能满足自己所需.这里就需要自定义绘图
原理:继承GMapRoute或者GMapMarker类,重写里面的OnRender函数.在OnRender函数里重新绘制所需的图形即可,OnRender函数里传参的是(Graphics g) 这是微软自己的类,可以在msdn上找到完整的绘图说明.相信用过c#绘图的同学一定很熟悉
GMapRoute和GMapMarker和区别在于,GMapRoute的构造函数是可以传一个PointLatLng链表进去,它的基类有自动将链表里甩的GPS坐标点全部转换为屏幕坐标系下的坐标点.以便使用Graphics进行绘图.而GMapMarker每次只能传参一个坐点进去,因为它目地只是为了操作一个点
下面帖上两段代码,继承GMapRoute的类是实现了在线上加了箭头,指明了路径的方向
继承GMapMarker的类是实现画圆,同时也实现在圆上指明了方向
说明:由于获取三角形三个点坐标使用到的向量,因此需要添加引用  System.Numerics.Vectors
建议使用NuGet安装
在NuGet中搜索 System.Numerics.Vectors ,下载第一个安装即可

namespace gMapActiveX.CustomMarkers
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Runtime.Serialization;
    using System.Windows.Forms;
    using GMap.NET;
    using GMap.NET.WindowsForms;
    /// <summary>
    /// GMap.NET route
    /// </summary>
    [Serializable]
    class MyGMapRoute : GMapRoute, ISerializable
    {
        /// <summary>
        /// specifies how the outline is painted
        /// </summary>
        [NonSerialized]
        public Pen MyStroke = DefaultStroke;//使用默认线属性
        public Brush Fill = new SolidBrush(Color.Yellow);//填充属性,用于箭头
        public int R = 14;//圆点半径
        public int Length = 20;//箭头三角形的宽度
        public bool TriangleIsVisible = true;//是否带箭头
        public bool DotIsVisible = true;//是否启用圆点
        static MyGMapRoute()
        {
            DefaultStroke.LineJoin = LineJoin.Round;
            DefaultStroke.Width = 5;
        }
        public MyGMapRoute(string name)
            : base(name)
        {
        }
        public MyGMapRoute(IEnumerable<PointLatLng> points, string name)
            : base(points, name)
        {
        }
        public MyGMapRoute(MapRoute oRoute)
            : base(oRoute)
        {
        }
        public override void OnRender(Graphics g)
        {
            if (IsVisible)
            {
                List<Point[]> pointsList = new List<Point[]>();
                Point[] pnts = new Point[LocalPoints.Count];
                for (int i = 0; i < LocalPoints.Count; i++)
                {
                    Point p2 = new Point((int)LocalPoints[i].X, (int)LocalPoints[i].Y );
                    pnts[pnts.Length - 1 - i] = p2;
                }
                if (pnts.Length > 1)
                {
                    g.DrawLines(Stroke, pnts);
                    for (int i = 1; i < pnts.Length; i++)
                    {
                        if(TriangleIsVisible)
                        {
                            Transfrom.GetTriangle(pnts[pnts.Length - 1 - i + 1], pnts[pnts.Length - 1 - i], Length, out PointF[] points);
                            g.FillPolygon(Fill, points);//画箭头
                        }
                        if(DotIsVisible)
                        {
                            g.FillEllipse(Fill, new Rectangle(pnts[pnts.Length - 1 - i].X - R / 2, pnts[pnts.Length - 1 - i].Y - R / 2, R, R));
                        }
                    }
                    if(DotIsVisible)
                    {
                        g.FillEllipse(Fill, new Rectangle(pnts[pnts.Length - 1].X - R / 2, pnts[pnts.Length - 1].Y - R / 2, R, R));
                    }
                }
            }
        }
        /// <summary>
        /// 释放颜色及资源
        /// </summary>
          #region IDisposable Members
        bool disposed = false;
        public override void Dispose()
        {
            if (Stroke != null)
            {
                Stroke.Dispose();
                Stroke = null;
            }
            if (Fill != null)
            {
                Fill.Dispose();
                Fill = null;
            }
            if (!disposed)
            {
                disposed = true;
                LocalPoints.Clear();
                base.Clear();
            }
        }
        #endregion
        #region ISerializable Members
        // Temp store for de-serialization.
        private GPoint[] deserializedLocalPoints;
        /// <summary>
        /// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
        /// </summary>
        /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data.</param>
        /// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization.</param>
        /// <exception cref="T:System.Security.SecurityException">
        /// The caller does not have the required permission.
        /// </exception>
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            info.AddValue("Visible", this.IsVisible);
            info.AddValue("LocalPoints", this.LocalPoints.ToArray());
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="GMapRoute"/> class.
        /// </summary>
        /// <param name="info">The info.</param>
        /// <param name="context">The context.</param>
        protected MyGMapRoute(SerializationInfo info, StreamingContext context) : base(info, context)
        {
            //this.Stroke = Extensions.GetValue<Pen>(info, "Stroke", new Pen(Color.FromArgb(144, Color.MidnightBlue)));
            this.IsVisible = Extensions.GetStruct<bool>(info, "Visible", true);
            this.deserializedLocalPoints = Extensions.GetValue<GPoint[]>(info, "LocalPoints");
        }
        #endregion
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Runtime.Serialization;
using GMap.NET;
using GMap.NET.WindowsForms;
namespace gMapActiveX.CustomMarkersCircle
{
#if !PocketPC
    [Serializable]
    public class MyGMapMarkerCircle : GMapMarker, ISerializable
#else
   public class GMapMarkerCircle : GMapMarker
#endif
    {
        /// <summary>
        /// In Meters 用米数确定圆
        /// </summary>
        public int Radius;
        /// <summary>
        /// 圆上是否要用箭头
        /// </summary>
        public enum Arrow {Empty,RightArrow,LeftArrow};
        public Arrow ArrowIsVisible = Arrow.Empty;
        /// <summary>
        /// 是否用米数确定圆
        /// </summary>
        public bool IsMeter = true;
        /// <summary>
        /// specifies how the outline is painted
        /// </summary>
        [NonSerialized]
#if !PocketPC
        public Pen Stroke = new Pen(Color.FromArgb(155, Color.MidnightBlue));
#else
      public Pen Stroke = new Pen(Color.MidnightBlue);
#endif
        /// <summary>
        /// 圆内填充颜色
        /// </summary>
        [NonSerialized]
#if !PocketPC
        public Brush Fill = new SolidBrush(Color.FromArgb(155, Color.AliceBlue));
        [NonSerialized]
        public Brush ArrowFill = new SolidBrush(Color.Yellow);
        public int Length = 20;//箭头三角形的宽度
#else
      public Brush Fill = new System.Drawing.SolidBrush(Color.AliceBlue);
#endif
        /// <summary>
        /// is filled
        /// </summary>
        public bool IsFilled = true;
        public MyGMapMarkerCircle(PointLatLng p,int r)
           : base(p)
        {
            Radius = r; // 0m
            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));
            if(ArrowIsVisible == Arrow.LeftArrow)
            {
                Transfrom.GetTriangle(new Point(LocalPosition.X + 10, LocalPosition.Y - R / 2), new Point(LocalPosition.X - 30, LocalPosition.Y - R / 2), Length, out PointF[] points);
                g.FillPolygon(ArrowFill, points);
            }
            if(ArrowIsVisible == Arrow.RightArrow)
            {
                Transfrom.GetTriangle(new Point(LocalPosition.X - 10, LocalPosition.Y - R / 2), new Point(LocalPosition.X + 30, LocalPosition.Y - R / 2), Length, out PointF[] points);
                g.FillPolygon(ArrowFill, points);
            }
        }
        public override void Dispose()
        {
            if (Stroke != null)
            {
                Stroke.Dispose();
                Stroke = null;
            }
            if (Fill != null)
            {
                Fill.Dispose();
                Fill = null;
            }
            base.Dispose();
        }
        public bool IsInside(PointLatLng p)
        {
            return (int)Overlay.Control.MapProvider.Projection.GetDistance(Position, p) * 1000 < Radius;
        }
#if !PocketPC
        #region ISerializable Members
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);
            // TODO: Radius, IsFilled
        }
        protected MyGMapMarkerCircle(SerializationInfo info, StreamingContext context)
           : base(info, context)
        {
            // TODO: Radius, IsFilled
        }
        #endregion
#endif
    }
}
绘制三角形,确定三个点的函数 代码参考 https://www.cnblogs.com/oY-CCTR/p/3755742.html
/// <summary>
        /// 返回一条线的终点位置的一个三角形的三个点坐标,三角形指向线的终点
        /// 三角形为一个正三角形
        /// </summary>
        /// <param name="start"></param>线起始点
        /// <param name="end"></param>线终点
        /// <param name="length"></param>三角形边长
        /// <param name="triangle"></param>输出的三角形的三个点数组
        public static void GetTriangle(Point start,Point end, int length, out PointF[] triangle)
        {
            triangle = new PointF[3];
            if (start == end)
            {
                return;
            }
            //箭头夹角
            double angle = 60.0 / 180 * Math.PI;
            //求BE长度
            double widthBE = length / 2 / (Math.Tan(angle / 2));
            //计算箭头的尖部位置点,这里取整条线段的1/4处
            PointF midPoint = new PointF((3*start.X + end.X) / 4, (3*start.Y + end.Y) / 4);
            //起点到箭头尖的向量
            Vector2 lineVector = new Vector2(midPoint.X - start.X, midPoint.Y - start.Y);
            //箭头尖到 三角形和直线垂直点 的向量
            Vector2 beVector = (float)widthBE * -Vector2.Normalize(lineVector);//需用到单位向量
            //三角形和直线和垂直点坐标
            PointF ePt = new PointF();
            //ePt - endPt = bcVector
            ePt.X = midPoint.X + beVector.X;
            ePt.Y = midPoint.Y + beVector.Y;
            //三角形和直线垂直线的向量
            Vector2 cdVector = new Vector2(-lineVector.Y, lineVector.X);
            //求CE向量
            Vector2 ceVector = length / 2 * Vector2.Normalize(cdVector);//需用到单位向量
            //求C点坐标,ePt - cPt = ceVector;
            PointF cPt = new PointF();
            cPt.X = ePt.X - ceVector.X;
            cPt.Y = ePt.Y - ceVector.Y;
            //求DE向量
            Vector2 deVector = length / 2 * -Vector2.Normalize(cdVector);//需用到单位向量
            //求D点,ePt-dPt = deVector;
            PointF dPt = new PointF();
            dPt.X = ePt.X - deVector.X;
            dPt.Y = ePt.Y - deVector.Y;
            triangle[0] = midPoint;
            triangle[1] = dPt;
            triangle[2] = cPt;
        }
GMap 自定义绘图的更多相关文章
- 【WPF学习】第六十八章 自定义绘图元素
		上一章分析了WPF元素的内部工作元素——允许每个元素插入到WPF布局系统的MeasureOverride()和ArrangeOverride()方法中.本章将进一步深入分析和研究元素如何渲染自身. 大 ... 
- 甘特图控件如何自定义绘图?DevExpress Winforms帮你忙
		DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpr ... 
- Revit中如何自定义快捷键
		最佳的绘图方式是左手键盘,右手鼠标,使用快捷键将大大提高绘图效率,Revit同样提供了自定义绘图工具快捷键的功能(Revit2011及以后版本),有两种方式调出自定义快捷键窗口,第一种是Revit窗口 ... 
- CorAnimation7-高效绘图、图像IO以及图层性能
		高效绘图 软件绘图 术语绘图通常在Core Animation的上下文中指代软件绘图(意即:不由GPU协助的绘图).在iOS中,软件绘图通常是由Core Graphics框架完成来完成.但是,在一些必 ... 
- UIKit和Core Graphics绘图(一)——字符串,线条,矩形,渐变
		概述 CoreGraphics也称为Quartz 2D 是UIKit下的主要绘图系统,频繁的用于绘制自定义视图.Core Graphics是高度集成于UIView和其他UIKit部分的.Core Gr ... 
- DX笔记之六------游戏画面绘图之透明特效的制作方法
		原文链接:http://blog.csdn.net/zhmxy555/article/details/7338082 透明效果 由于所有的图文件都是以矩形来储存的,我们也许会需要把一张怪兽图片贴到窗口 ... 
- DX笔记之五------游戏画面绘图之绘制位图
		本系列文章由zhmxy555编写,转载请注明出处. http://blog.csdn.net/zhmxy555/article/details/7335103 共四步 步骤一:加载位图 步骤二:建立与 ... 
- [iOS Animation]-CALayer 绘图效率
		绘图 不必要的效率考虑往往是性能问题的万恶之源. ——William Allan Wulf 在第12章『速度的曲率』我们学习如何用Instruments来诊断Core Animation性能问题.在构 ... 
- Qt之自定义检索框
		1.效果展示 今天这篇文章主要讲解的是自定义搜索框,不仅仅支持搜索,而且可以支持搜索预览,具体请看效果图1.网上也有一些比较简单明了的自定义搜索框,比如Qt之自定义搜索框,讲的也比较详细,不过本文的侧 ... 
随机推荐
- Swagger 生成API文档
			1.打开程序包管理控制台输入: Install-Package Swashbuckle 2.打开App_Start文件夹下的SwaggerConfig.cs文件找到 c.IncludeXmlComme ... 
- WPF旋转的界面实现
			原文:WPF旋转的界面实现 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/details/1821534 ... 
- React HOC
			在React官网文档学习React HOC,整个看了一遍还是云里雾里的,于是按照官网文档,自己动手实践一下.官网地址:React 高阶组件 定义:高阶组件就是一个函数,且该函数接受一个组件作为参数,并 ... 
- 人活着系列Tanya和蔡健雅猪 (floyd)
			人活着系列之芳姐和芳姐的猪 Time Limit: 1000MS Memory limit: 65536K 题目描写叙述 芳姐特别喜欢猪,所以,她特意养了m个猪圈,顺便在k条无向边,每条边有都有起点v ... 
- libuv和libev 异步I/O库的比较
			libuv 和 libev ,两个名字相当相近的 I/O Library,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述. 高性能网络编程这个话题已经 ... 
- WPF学习笔记:(一)数据绑定与DataContext
			前一段半心半意地学习了一下WPF,是从控件入手的,发现巨容易,甚至有些无趣.昨天面试,被问到了很多WPF的特性的东西,直接就傻了.于是乎,还是要去深刻的学习一下WPF.刚刚试了一下数据绑定,几次都没有 ... 
- MEF 插件式开发 - WPF 初体验
			原文:MEF 插件式开发 - WPF 初体验 目录 MEF 在 WPF 中的简单应用 加载插件 获取元数据 依赖注入 总结 MEF 在 WPF 中的简单应用 MEF 的开发模式主要适用于插件化的业务场 ... 
- 利用Python sklearn的SVM对AT&T人脸数据进行人脸识别
			要求:使用10-fold交叉验证方法实现SVM的对人脸库识别,列出不同核函数参数对识别结果的影响,要求画对比曲线. 使用Python完成,主要参考文献[4],其中遇到不懂的功能函数一个一个的查官方文档 ... 
- SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database)
			原文:SQL Server 游标运用:查看一个数据库所有表大小信息(Sizes of All Tables in a Database) 一.本文所涉及的内容(Contents) 本文所涉及的内容(C ... 
- DELPHI编写服务程序总结(在系统服务和桌面程序之间共享内存,在服务中使用COM组件)
			DELPHI编写服务程序总结 一.服务程序和桌面程序的区别 Windows 2000/XP/2003等支持一种叫做“系统服务程序”的进程,系统服务和桌面程序的区别是:系统服务不用登陆系统即可运行:系统 ... 
