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 自定义绘图的更多相关文章

  1. 【WPF学习】第六十八章 自定义绘图元素

    上一章分析了WPF元素的内部工作元素——允许每个元素插入到WPF布局系统的MeasureOverride()和ArrangeOverride()方法中.本章将进一步深入分析和研究元素如何渲染自身. 大 ...

  2. 甘特图控件如何自定义绘图?DevExpress Winforms帮你忙

    DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpr ...

  3. Revit中如何自定义快捷键

    最佳的绘图方式是左手键盘,右手鼠标,使用快捷键将大大提高绘图效率,Revit同样提供了自定义绘图工具快捷键的功能(Revit2011及以后版本),有两种方式调出自定义快捷键窗口,第一种是Revit窗口 ...

  4. CorAnimation7-高效绘图、图像IO以及图层性能

    高效绘图 软件绘图 术语绘图通常在Core Animation的上下文中指代软件绘图(意即:不由GPU协助的绘图).在iOS中,软件绘图通常是由Core Graphics框架完成来完成.但是,在一些必 ...

  5. UIKit和Core Graphics绘图(一)——字符串,线条,矩形,渐变

    概述 CoreGraphics也称为Quartz 2D 是UIKit下的主要绘图系统,频繁的用于绘制自定义视图.Core Graphics是高度集成于UIView和其他UIKit部分的.Core Gr ...

  6. DX笔记之六------游戏画面绘图之透明特效的制作方法

    原文链接:http://blog.csdn.net/zhmxy555/article/details/7338082 透明效果 由于所有的图文件都是以矩形来储存的,我们也许会需要把一张怪兽图片贴到窗口 ...

  7. DX笔记之五------游戏画面绘图之绘制位图

    本系列文章由zhmxy555编写,转载请注明出处. http://blog.csdn.net/zhmxy555/article/details/7335103 共四步 步骤一:加载位图 步骤二:建立与 ...

  8. [iOS Animation]-CALayer 绘图效率

    绘图 不必要的效率考虑往往是性能问题的万恶之源. ——William Allan Wulf 在第12章『速度的曲率』我们学习如何用Instruments来诊断Core Animation性能问题.在构 ...

  9. Qt之自定义检索框

    1.效果展示 今天这篇文章主要讲解的是自定义搜索框,不仅仅支持搜索,而且可以支持搜索预览,具体请看效果图1.网上也有一些比较简单明了的自定义搜索框,比如Qt之自定义搜索框,讲的也比较详细,不过本文的侧 ...

随机推荐

  1. WPF 多点触摸开发[2]:WPF触摸的几个手势的执行顺序

    原文:WPF 多点触摸开发[2]:WPF触摸的几个手势的执行顺序 前面我讲了在win7下使用模拟器,进行调试模拟多点触摸,其实际开发中这样也比较麻烦.. 要拿几个鼠标. 所以更多的人会 买个触摸套 套 ...

  2. WPF最大化避免覆盖任务栏

    原文:WPF最大化避免覆盖任务栏 WPF当窗体WindowStyle=”None”时,最大化会覆盖掉任务栏.如何解决这个问题呢? 我在Google里面搜到一篇文章,要用到Win32 API,通过让WP ...

  3. Aspect Oriented Programming面向切面编程

    I简介 Aspect Oriented Programming(AOP),面向切面编程,是一个比较热门的话题.AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或 ...

  4. python selenium chrome 测试

    #coding=utf-8 from selenium import webdriver from selenium.webdriver.common.keys import Keys from se ...

  5. 通过Chrome扩展来批量复制知乎好友

        1.初始化文件 Chrome 官方扩展教程地址 新建一个文件夹 zhi-follow 下图中 1 部分为 默认的图标3种尺寸 会显示在 Chrome 中   2. 定义按钮样式   页面上会有 ...

  6. Substring详解

    class Program { static void Main(string[] args) { string str = "Hello World!"; ; //Substri ...

  7. Caliburn.Micro 自定义View和ViewModel的匹配规则

    使用TypeMappingConfiguration类 //Override the default subnamespaces var config = new TypeMappingConfigu ...

  8. UWP中弹出框屏幕适配问题

    上次在UWP中的消息提示框(二)中谈到弹出框在虚拟导航栏的手机上被遮挡问题,今天接就着扯. 上次给用户控件指定的宽高都是Window.Current.Bounds的宽高,而这个获取到的是包含应用程序窗 ...

  9. 我写的一个Qt 显示二维码( QR Code)的控件(可以去掉对 libpthread 的依赖,而且编译出的库文件可以在 vc2010 的release 模式下使用)

    最近一个项目需要显示二维码,所以花了点时间(只用了一个晚上,写的很不完善),写了个显示二维码的控件.当然这个控件用到了些开源的代码,比如qrencode,所以我也打算把我的代码开源. 我的代码参考了 ...

  10. QString之simplified()用于读取数据、规范数据,非常方便

    在工程项目开发中,遇到这么个问题:手工计入文件中的数据,每行有三个,前两个是数字,最后一个是标识,现在把这3个数据提取出来. 一提取就出现问题了:由于手工导入,数据间使用空白间隔,有可能是一个空格,有 ...