基于GMap.NET库实现的Windows桌面地图工具软件分享

article/2025/11/11 7:30:45

0 前言

由于工作中经常和地图、GPS坐标转换、GPS轨迹查看等内容相关,经常要借助一些在线网站和工具来查看地图和位置等,在一次偶然的机会中了解到一个GMap.NET开源的桌面地图库和基于GMap.NET实现的MapDownloader地图下载工具,于是也想实现一个自己的地图相关工具,包含以下功能:

  • 多种地图切换:Baidu(百度), Amap(高德), Tencent(腾讯), Tianditu(天地图), Ship, Google, Bing, OpenStreetMap, ArcGIS, Here(Nokia)等;
  • 坐标拾取和坐标转换:GPS(WGS84)、火星坐标(GCJ02)、百度坐标(BD09)等相互转换,地理编码和反地理编码等;
  • POI查询:通过百度地图、高德地图、腾讯地图等WebAPI搜索、保存POI数据;
  • 地图下载、拼接:通过矩形、多边形、行政区划等方式下载、缓存地图数据或者拼接成大图;
  • 导航路线搜索、导出:通过百度地图、高德地图、腾讯地图等WebAPI搜索、保存导航路线数据;
  • 历史轨迹加载、回放:加载不同格式(csv/excel/nmea)轨迹数据,并可以回放、测试等;
  • 实时轨迹显示:通过串口接收GPS信息显示在地图上;

项目地址:https://github.com/luotengyuan/MyMapTools、https://gitee.com/luotengyuan/MyMapTools
程序下载:https://download.csdn.net/download/loutengyuan/86507941

catch_2022-12-26_17-16-41

声明:本软件仅供个人学习与科研使用,所下载的数据版权归各个地图服务商所有,任何组织或个人因数据使用不当造成的问题,软件作者不负责任。

PS: 请替换自己的API Key!

  • http://lbsyun.baidu.com/index.php?title=webapi

  • https://lbs.amap.com/api/webservice/summary/

  • https://lbs.qq.com/webservice_v1/index.html

    GIF_2022-12-26_17-19-30

    最近有人使用我在工程中配置的key去请求搜索服务,我的也是个人开发账号,配额才100,导致我天天收到短信和邮件提示,所以需要使用的朋友还是自己申请一下key,谢谢!

    catch_2022-12-26_18-40-03

    catch_2022-12-26_18-43-21

1 功能介绍

1.1 多种在线地图切换

  • 可以根据自己的需要切换不同的地图提供商(例如:百度、高德)或者不同的地图类型(例如:普通地图、卫星地图、混合地图)

GIF_2022-12-26_17-26-08

1.2 经纬度坐标显示

  • 可以根据不同类型的经纬度坐标,将坐标标注到地图上显示
    GIF_2022-12-26_17-30-22

1.3 坐标拾取功能

  • 在地图指定点右键鼠标,选择拾取该点坐标和地址菜单,可以在坐标坐标拾取标签页下查看该点的坐标和地址
    GIF_2022-12-26_18-07-41
  • 根据坐标和地址也可查询在地图上的点位
    GIF_2022-12-26_18-35-43

1.4 POI查询功能

  • 根据关键字查询POI,并在地图中标注显示,还可以将搜索结果导出成Excel文件
    GIF_2022-12-26_17-36-04

1.5 地图下载拼接

  • 可以根据绘制矩形和多边形下载指定区域地图,可以根据行政区划下载地图
    GIF_2022-12-26_17-38-08
    GIF_2022-12-26_17-40-41

1.6 导航路线规划

  • 地图上右键选取导航起点、途经点、终点,点击规划路线,生成一条导航路线
    GIF_2022-12-26_17-43-01
  • 可以将导航路线导出成轨迹点
    GIF_2022-12-26_17-44-45
  • 还可以将轨迹导出成文件
    GIF_2022-12-26_17-47-25
  • 文件格式如下
    在这里插入图片描述

1.7 历史轨迹加载与回放

  • 可以通过加载csv、excel、nmea等文件将历史轨迹显示到地图上
    GIF_2022-12-26_17-55-33
  • 可以将历史轨迹设置成模拟轨迹,模拟历史数据,并将模拟信息通过Pipe方式发送到其他进程作为输入,进行模拟GPS测试
    GIF_2022-12-26_17-58-03

1.8 串口接收实时轨迹

  • 可以根据串口接收到的NMEA或者其他指定格式实时定位信息,并显示到地图上

GIF_2022-12-26_18-05-19

2 代码实现

2.1 GMap.NET库使用

GMap.NET是一个强大、免费、跨平台、开源的.NET控件,它在Windows Forms和WPF环境中使用Google, Yahoo!, Bing, OpenStreetMap, ArcGIS, Pergo, SigPac等路径规划、地理编码以及地图展示功能。下面介绍从下载安装到如何使用GMap.NET。

2.1.1 下载和安装

从这里下载,解压后得到两个文件(GMap.NET.Core.dll 和 GMap.NET.WindowsForms.dll)。然后在项目中添加引用。
在这里插入图片描述
添加GMapControl到工具箱。在“选择项”时,选择“GMap.NET.WindowsForms.dll”文件即可添加。
在这里插入图片描述
使用NUGET安装
在这里插入图片描述

2.1.2 添加地图控件

拖拽GMapControl到Windows Form中,可看到控件中心有个小十字。查看属性,你会发现GMap.NET的一些特有属性。通过设置这些属性可以配置地图的行为,但是不能设置其内容。
在这里插入图片描述

  • Bearing - 按照指定的度数向左旋转地图
  • CanDragMap – 是否启用鼠标右键拖动(平移)地图
  • EmptyTileColor – 设置没有数据的切片所显示的颜色
  • MarkersEnabled – 是否显示定义的标记,同PolygonsEnabled和RoutesEnabled
  • ShowTileGridLines – 显示网格线
  • Zoom,MinZoom和MaxZoom - 缩放级别

GMap.NET支持多种地图源,定义地图源需要在代码中去设置。可以在GMapControl的 Load 事件中添加如下代码:

this.gMapControl1.MapProvider = OpenStreet4UMapProvider.Instance; // 设置地图源
GMaps.Instance.Mode = AccessMode.ServerAndCache; // GMap工作模式
this.gMapControl1.SetPositionByKeywords("北京"); // 地图中心位置//使用经纬度设置地图中心
//this.gMapControl1.Position = new GMap.NET.PointLatLng(39.923518, 116.539009);

① MapProvider:设置地图源,输入GMapProviders可以看到GMap所支持的所有地图源。
在这里插入图片描述
② GMaps.Instance.Mode: GMap可以从服务器、本地缓存、服务器或本地缓存获取数据。这适用于在应用程序中创建的所有GMap控件实例,只需要设置一次该值。
在这里插入图片描述
③ 设置地图中心位置可以使用关键字或者经纬度。
④ 地图显示结果。按住鼠标右键可以拖拽地图,当然也可以设置其他键来拖拽。

this.gMapControl1.DragButton = MouseButtons.Left;

在这里插入图片描述

2.1.3 添加标记

//创建一个名为“markers”的图层
GMapOverlay markers = new GMapOverlay("markers");
//创建标记,并设置位置及样式
GMapMarker marker = new GMarkerGoogle(new PointLatLng(39.923518, 116.539009), GMarkerGoogleType.blue_pushpin);
//将标记添加到图层
markers.Markers.Add(marker);
//将图层添加到地图
this.gMapControl1.Overlays.Add(markers);

① GMapOverlay:图层。添加的标记、图形、路径等都是在图层上操作的。
② GMapMarker:GMarkerGoogle,提供标记位置(PointLatLng)和标记样式。 它有两个重载,可以使用GMarkerGoogleType和位图。GMap.NET还提供了GMarkerCross,这是一个简单的十字,不允许使用图标。

public GMarkerGoogle(PointLatLng p, GMarkerGoogleType type);
public GMarkerGoogle(PointLatLng p, Bitmap Bitmap);

GMapMarker还可以设置ToolTip。

marker.ToolTipText = "我在这里";
marker.ToolTip.Fill = new SolidBrush(Color.FromArgb(100, Color.Black));
marker.ToolTip.Foreground = Brushes.White;
marker.ToolTip.TextPadding = new Size(20, 20);

③ 地图显示结果。(发现中心的小十字没了吗,因为这是可以设置的)
在这里插入图片描述

this.gMapControl1.ShowCenter = false; //隐藏中心十字

④ 标记点击事件
标记本身没有任何事件钩子,GMapControl的OnMarkerClick事件即为标记点击事件。在下面的示例中,点击标记会弹出提示框显示ToolTip的文本内容。当然GMap.NET不只有点击事件,还有OnMarkerEnter、OnMarkerLeave。

private void gMapControl1_OnMarkerClick(GMapMarker item, MouseEventArgs e)
{MessageBox.Show(String.Format("Marker:{0} 被点了。", item.ToolTipText));
}

2.1.4 添加多边形

添加多边形和添加标记的原理是一样的。

GMapOverlay polygons = new GMapOverlay("polygons");
// 多边形的顶点
List<PointLatLng> points = new List<PointLatLng>();
points.Add(new PointLatLng(39.92244, 116.3922));
points.Add(new PointLatLng(39.92280, 116.4015));
points.Add(new PointLatLng(39.91378, 116.4019));
points.Add(new PointLatLng(39.91346, 116.3926));
GMapPolygon polygon = new GMapPolygon(points, "故宫");
polygon.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
polygon.Stroke = new Pen(Color.Red, 1);
polygons.Polygons.Add(polygon);
this.gMapControl1.Overlays.Add(polygons);

显示结果。
在这里插入图片描述

版权声明:以上内容参考huangli0原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
链接:https://blog.csdn.net/huangli0/article/details/80147243

2.2 坐标转换

坐标转换包含CoordType.cs、PointLatLng.cs、CoordinateTransform.cs、PointInDiffCoord.cs四个类,分别作用和代码如下:

CoordType.cs:坐标类型定义
PointLatLng.cs:经纬度封装类
CoordinateTransform.cs:不同坐标转换工具类
PointInDiffCoord.cs:不同坐标转换封装类

  • CoordType.cs 代码如下:
using System;
using System.Collections.Generic;
using System.Text;namespace GMap.NET
{/// <summary>/// 坐标系类型/// </summary>public enum CoordType{WGS84,GCJ02,BD09,UNKNOW}
}
  • PointLatLng.cs 代码如下:
namespace GMap.NET
{using System;using System.Globalization;/// <summary>/// the point of coordinates/// </summary>[Serializable]public struct PointLatLng{public static readonly PointLatLng Empty = new PointLatLng();private double lat;private double lng;private CoordType type;bool NotEmpty;public PointLatLng(double lat, double lng){this.lat = lat;this.lng = lng;this.type = CoordType.UNKNOW;NotEmpty = true;}public PointLatLng(double lat, double lng, CoordType type) : this(lat, lng){this.type = type;}/// <summary>/// returns true if coordinates wasn't assigned/// </summary>public bool IsEmpty{get{return !NotEmpty;}}public double Lat{get{return this.lat;}set{this.lat = value;NotEmpty = true;}}public double Lng{get{return this.lng;}set{this.lng = value;NotEmpty = true;}}public CoordType Type{get{return this.type;}set{this.type = value;}}public static PointLatLng operator +(PointLatLng pt, SizeLatLng sz){return Add(pt, sz);}public static PointLatLng operator -(PointLatLng pt, SizeLatLng sz){return Subtract(pt, sz);}public static SizeLatLng operator -(PointLatLng pt1, PointLatLng pt2){return new SizeLatLng(pt1.Lat - pt2.Lat, pt2.Lng - pt1.Lng);}public static bool operator ==(PointLatLng left, PointLatLng right){return ((left.Lng == right.Lng) && (left.Lat == right.Lat));}public static bool operator !=(PointLatLng left, PointLatLng right){return !(left == right);}public static PointLatLng Add(PointLatLng pt, SizeLatLng sz){return new PointLatLng(pt.Lat - sz.HeightLat, pt.Lng + sz.WidthLng);}public static PointLatLng Subtract(PointLatLng pt, SizeLatLng sz){return new PointLatLng(pt.Lat + sz.HeightLat, pt.Lng - sz.WidthLng);}public override bool Equals(object obj){if(!(obj is PointLatLng)){return false;}PointLatLng tf = (PointLatLng)obj;return (((tf.Lng == this.Lng) && (tf.Lat == this.Lat)) && tf.GetType().Equals(base.GetType()));}public void Offset(PointLatLng pos){this.Offset(pos.Lat, pos.Lng);}public void Offset(double lat, double lng){this.Lng += lng;this.Lat -= lat;}public override int GetHashCode(){return (this.Lng.GetHashCode() ^ this.Lat.GetHashCode());}public override string ToString(){return string.Format(CultureInfo.CurrentCulture, "{{Lat={0}, Lng={1}}}", this.Lat, this.Lng);}}
}

CoordinateTransform.cs 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace GMap.NET
{/// <summary>/// 各坐标系统转换 /// WGS84坐标系:即地球坐标系,国际上通用的坐标系。设备一般包含GPS芯片或者北斗芯片获取的经纬度为WGS84地理坐标系, /// 谷歌地图采用的是WGS84地理坐标系(中国范围除外); /// GCJ02坐标系:即火星坐标系,是由中国国家测绘局制订的地理信息系统的坐标系统。由WGS84坐标系经加密后的坐标系。 /// 高德地图、腾讯地图、谷歌中国地图采用的是GCJ02地理坐标系; /// BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系; /// 搜狗坐标系、图吧坐标系等,估计也是在GCJ02基础上加密而成的。/// </summary>public static class CoordinateTransform{/// <summary>/// 检查坐标是否在中国范围内/// </summary>/// <param name="lat">latitude 纬度</param>/// <param name="lng">longitude 经度</param>/// <returns></returns>private static bool OutOfChina(double lat, double lng){if (lng < 72.004 || lng > 137.8347)return true;if (lat < 0.8293 || lat > 55.8271)return true;return false;}/// <summary>/// 火星坐标(GCJ02)转换为WGS坐标/// </summary>/// <param name="lngMars">火星坐标经度longitude</param>/// <param name="latMars">火星坐标纬度latitude</param>/// <param name="lngWgs">WGS经度</param>/// <param name="latWgs">WGS纬度</param>public static void ConvertGcj02ToWgs84(double lngMars, double latMars, out double lngWgs, out double latWgs){lngWgs = lngMars;latWgs = latMars;double lngtry = lngMars;double lattry = latMars;ConvertWgs84ToGcj02(lngMars, latMars, out lngtry, out lattry);double dx = lngtry - lngMars;double dy = lattry - latMars;lngWgs = lngMars - dx;latWgs = latMars - dy;}/// <summary>/// WGS坐标转换为火星坐标(GCJ02)/// </summary>/// <param name="lngWgs">WGS经度</param>/// <param name="latWgs">WGS纬度</param>/// <param name="lngMars">火星坐标经度</param>/// <param name="latMars">火星坐标纬度</param>public static void ConvertWgs84ToGcj02(double lngWgs, double latWgs, out double lngMars, out double latMars){lngMars = lngWgs;latMars = latWgs;const double pi = 3.14159265358979324;//// Krasovsky 1940//// a = 6378245.0, 1/f = 298.3// b = a * (1 - f)// ee = (a^2 - b^2) / a^2;const double a = 6378245.0;const double ee = 0.00669342162296594323;if (lngWgs < 72.004 || lngWgs > 137.8347)return;if (latWgs < 0.8293 || latWgs > 55.8271)return;double x = 0, y = 0;x = lngWgs - 105.0;y = latWgs - 35.0;double dLon = 300.0 + 1.0 * x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.Sqrt(Math.Abs(x));dLon += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;dLon += (20.0 * Math.Sin(x * pi) + 40.0 * Math.Sin(x / 3.0 * pi)) * 2.0 / 3.0;dLon += (150.0 * Math.Sin(x / 12.0 * pi) + 300.0 * Math.Sin(x / 30.0 * pi)) * 2.0 / 3.0;double dLat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.Sqrt(Math.Abs(x));dLat += (20.0 * Math.Sin(6.0 * x * pi) + 20.0 * Math.Sin(2.0 * x * pi)) * 2.0 / 3.0;dLat += (20.0 * Math.Sin(y * pi) + 40.0 * Math.Sin(y / 3.0 * pi)) * 2.0 / 3.0;dLat += (160.0 * Math.Sin(y / 12.0 * pi) + 320.0 * Math.Sin(y * pi / 30.0)) * 2.0 / 3.0;double radLat = latWgs / 180.0 * pi;double magic = Math.Sin(radLat);magic = 1 - ee * magic * magic;double sqrtMagic = Math.Sqrt(magic);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.Cos(radLat) * pi);dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);lngMars = lngWgs + dLon;latMars = latWgs + dLat;}/// <summary>/// 火星坐标(GCJ02)转换为baidu坐标/// </summary>/// <param name="lngMars"></param>/// <param name="latMars"></param>/// <param name="lngBaidu"></param>/// <param name="latBaidu"></param>public static void ConvertGcj02ToBd09(double lngMars, double latMars, out double lngBaidu, out double latBaidu){const double x_pi = 3.14159265358979324 * 3000.0 / 180.0;//const double x_pi = 3.14159265358979324;double x = lngMars;double y = latMars;double z = Math.Sqrt(x * x + y * y) + 0.00002 * Math.Sin(y * x_pi);double theta = Math.Atan2(y, x) + 0.000003 * Math.Cos(x * x_pi);lngBaidu = z * Math.Cos(theta) + 0.0065;latBaidu = z * Math.Sin(theta) + 0.006;}/// <summary>/// baidu坐标转换为火星坐标(GCJ02)/// </summary>/// <param name="lngBaidu"></param>/// <param name="latBaidu"></param>/// <param name="lngMars"></param>/// <param name="latMars"></param>public static void ConvertBd09ToGcj02(double lngBaidu, double latBaidu, out double lngMars, out double latMars){const double x_pi = 3.14159265358979324 * 3000.0 / 180.0;double x = lngBaidu - 0.0065;double y = latBaidu - 0.006;double z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * x_pi);double theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * x_pi);lngMars = z * Math.Cos(theta);latMars = z * Math.Sin(theta);}/// <summary>/// WGS坐标转换为baidu坐标/// </summary>/// <param name="lngWgs"></param>/// <param name="latWgs"></param>/// <param name="lngBaidu"></param>/// <param name="latBaidu"></param>public static void ConvertWgs84ToBd09(double lngWgs, double latWgs, out double lngBaidu, out double latBaidu){double lng;double lat;ConvertWgs84ToGcj02(lngWgs, latWgs, out lng, out lat);ConvertGcj02ToBd09(lng, lat, out lngBaidu, out latBaidu);}/// <summary>/// baidu坐标转换为WGS坐标/// </summary>/// <param name="lngBaidu"></param>/// <param name="latBaidu"></param>/// <param name="lngWgs"></param>/// <param name="latWgs"></param>public static void ConvertBd09ToWgs84(double lngBaidu, double latBaidu,out double lngWgs, out double latWgs){double lng;double lat;ConvertBd09ToGcj02(lngBaidu, latBaidu, out lng, out lat);ConvertGcj02ToWgs84(lng, lat, out lngWgs, out latWgs);}}
}

PointInDiffCoord.cs 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GMap.NET;
using GMapPositionFix;namespace GMapCommonType
{public class PointInDiffCoord{private PointLatLng wgs84; public PointLatLng WGS84{get{double lon, lat;if (CoordType == CoordType.WGS84){return wgs84;}else if (CoordType == CoordType.GCJ02){if (wgs84 == PointLatLng.Empty){CoordinateTransform.ConvertGcj02ToWgs84(gcj02.Lng, gcj02.Lat, out lon, out lat);wgs84.Lat = lat;wgs84.Lng = lon;}return wgs84;}else if (CoordType == CoordType.BD09){if (wgs84 == PointLatLng.Empty){CoordinateTransform.ConvertBd09ToWgs84(bd09.Lng, bd09.Lat, out lon, out lat);wgs84.Lat = lat;wgs84.Lng = lon;}return wgs84;}else{return PointLatLng.Empty;}}}private PointLatLng gcj02;public PointLatLng GCJ02{get{double lon, lat;if (CoordType == CoordType.WGS84){if (gcj02 == PointLatLng.Empty){CoordinateTransform.ConvertWgs84ToGcj02(wgs84.Lng, wgs84.Lat, out lon, out lat);gcj02.Lat = lat;gcj02.Lng = lon;}return gcj02;}else if (CoordType == CoordType.GCJ02){return gcj02;}else if (CoordType == CoordType.BD09){if (gcj02 == PointLatLng.Empty){CoordinateTransform.ConvertBd09ToGcj02(bd09.Lng, bd09.Lat, out lon, out lat);gcj02.Lat = lat;gcj02.Lng = lon;}return gcj02;}else{return PointLatLng.Empty;}}}private PointLatLng bd09;public PointLatLng BD09{get{double lon, lat;if (CoordType == CoordType.WGS84){if (bd09 == PointLatLng.Empty){CoordinateTransform.ConvertWgs84ToBd09(wgs84.Lng, wgs84.Lat, out lon, out lat);bd09.Lat = lat;bd09.Lng = lon;}return bd09;}else if (CoordType == CoordType.GCJ02){if (bd09 == PointLatLng.Empty){CoordinateTransform.ConvertGcj02ToBd09(gcj02.Lng, gcj02.Lat, out lon, out lat);bd09.Lat = lat;bd09.Lng = lon;}return bd09;}else if (CoordType == CoordType.BD09){return bd09;}else{return PointLatLng.Empty;}}}public CoordType CoordType;public PointInDiffCoord(){wgs84 = PointLatLng.Empty;gcj02 = PointLatLng.Empty;bd09 = PointLatLng.Empty;CoordType = CoordType.UNKNOW;}/// <summary>/// 构造方法/// </summary>/// <param name="p"></param>public PointInDiffCoord(PointLatLng p){if (p.Type == CoordType.WGS84){wgs84 = p;gcj02 = PointLatLng.Empty;bd09 = PointLatLng.Empty;CoordType = CoordType.WGS84;}else if (p.Type == CoordType.GCJ02){wgs84 = PointLatLng.Empty;gcj02 = p;bd09 = PointLatLng.Empty;CoordType = CoordType.GCJ02;}else if (p.Type == CoordType.BD09){wgs84 = PointLatLng.Empty;gcj02 = PointLatLng.Empty;bd09 = p;CoordType = CoordType.BD09;}else{wgs84 = PointLatLng.Empty;gcj02 = PointLatLng.Empty;bd09 = PointLatLng.Empty;CoordType = CoordType.UNKNOW;}}/// <summary>/// 构造方法/// </summary>/// <param name="lat"></param>/// <param name="lon"></param>public PointInDiffCoord(double lat, double lon): this(new PointLatLng(lat, lon)){}public static PointLatLng GetWGS84Point(PointLatLng p){double lon, lat;if (p != PointLatLng.Empty){if (p.Type == CoordType.WGS84){return p;}else if (p.Type == CoordType.GCJ02){CoordinateTransform.ConvertGcj02ToWgs84(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.WGS84);}else if (p.Type == CoordType.BD09){CoordinateTransform.ConvertBd09ToWgs84(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.WGS84);}else{return PointLatLng.Empty;}}else{return PointLatLng.Empty;}}public static PointLatLng GetGCJ02Point(PointLatLng p){double lon, lat;if (p != PointLatLng.Empty){if (p.Type == CoordType.WGS84){CoordinateTransform.ConvertWgs84ToGcj02(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.GCJ02);}else if (p.Type == CoordType.GCJ02){return p;}else if (p.Type == CoordType.BD09){CoordinateTransform.ConvertBd09ToGcj02(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.GCJ02);}else{return PointLatLng.Empty;}}else{return PointLatLng.Empty;}}public static PointLatLng GetBD09Point(PointLatLng p){double lon, lat;if (p != PointLatLng.Empty){if (p.Type == CoordType.WGS84){CoordinateTransform.ConvertWgs84ToBd09(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.BD09);}else if (p.Type == CoordType.GCJ02){CoordinateTransform.ConvertGcj02ToBd09(p.Lng, p.Lat, out lon, out lat);return new PointLatLng(lat, lon, CoordType.BD09);}else if (p.Type == CoordType.BD09){return p;}else{return PointLatLng.Empty;}}else{return PointLatLng.Empty;}}public static PointLatLng GetPointInCoordType(PointLatLng p, CoordType destType){if (destType == CoordType.WGS84){return GetWGS84Point(p);}else if (destType == CoordType.GCJ02){return GetGCJ02Point(p);}else if (destType == CoordType.BD09){return GetBD09Point(p);}else{return p;}}public static PointLatLng GetPointInCoordType(PointLatLng p, CoordType srcType, CoordType destType){p.Type = srcType;if (destType == CoordType.WGS84){return GetWGS84Point(p);}else if (destType == CoordType.GCJ02){return GetGCJ02Point(p);}else if (destType == CoordType.BD09){return GetBD09Point(p);}else{return p;}}public static PointLatLng GetPointInCoordType(double lat, double lon, CoordType srcType, CoordType destType){PointLatLng p = new PointLatLng(lat, lon, srcType);if (destType == CoordType.WGS84){return GetWGS84Point(p);}else if (destType == CoordType.GCJ02){return GetGCJ02Point(p);}else if (destType == CoordType.BD09){return GetBD09Point(p);}else{return p;}}public static List<PointLatLng> GetPointListInCoordType(List<PointLatLng> pList, CoordType srcType, CoordType destType){if (srcType == destType){return pList;}List<PointLatLng> retList = new List<PointLatLng>();foreach (var item in pList){retList.Add(GetPointInCoordType(item, srcType, destType));}return retList;}}
}
  • 坐标转换示例代码:
// 创建一个GCJ02坐标
PointLatLng p = new PointLatLng(25.254845, 118.658454, CoordType.GCJ02);
// 获取指定类型坐标点
PointLatLng p_type = PointInDiffCoord.GetPointInCoordType(p, type);
// 通过GCJ02坐标点创建PointInDiffCoord对象
PointInDiffCoord pidc = new PointInDiffCoord(p);
// 获取WGS84坐标
PointLatLng p_wgs = pidc.WGS84;
// 获取GCJ02坐标
PointLatLng p_gcj = pidc.GCJ02;
// 获取BD09坐标
PointLatLng p_bd = pidc.BD09;

2.4 模拟跑车

使用历史轨迹进行模拟跑车时,程序将创建NamedPipeServer服务,将GPS信息发送出来,其他进程或程序可以通过连接该服务接收GPS信息,NamedPipeServer服务代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Pipes;
using System.Threading;namespace MapToolsWinForm
{/// <summary>/// Windows命名管道服务类/// </summary>class NamedPipeServer{private NamedPipeServerStream serverStream;private string pipeName;private Thread connThread;private Thread sendThread;private int sleepTime = 10;public NamedPipeServer(string pipeName){this.pipeName = pipeName;serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 254, PipeTransmissionMode.Message);connThread = new Thread(ConnThreadTask);connThread.Start();sendThread = new Thread(SendThreadTask);sendThread.Start();}private void ConnThreadTask(object obj){while (true){if (!serverStream.IsConnected){try{serverStream.WaitForConnection();sendQueue.Clear();}catch (Exception){serverStream.Disconnect();serverStream.Dispose();serverStream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Message);}}Thread.Sleep(sleepTime);}}Queue<string> sendQueue = new Queue<string>();private void SendThreadTask(object obj){while (true){try{if (!serverStream.IsConnected){Thread.Sleep(sleepTime);continue;}if (sendQueue.Count <= 0){Thread.Sleep(sleepTime);continue;}string send_str = sendQueue.Dequeue();byte[] byteArr = Encoding.UTF8.GetBytes(send_str);serverStream.Write(byteArr, 0, byteArr.Length);serverStream.Flush();Thread.Sleep(sleepTime);}catch (Exception ex){}}}public bool sendCanData(string send_str){if (!serverStream.IsConnected){return false;}lock (sendQueue){if (sendQueue.Count > 20){sendQueue.Clear();}sendQueue.Enqueue(send_str);}return true;}public void Close(){if (connThread != null && connThread.IsAlive){connThread.Abort();}if (sendThread != null && sendThread.IsAlive){sendThread.Abort();}if (sendQueue != null && sendQueue.Count > 0){sendQueue.Clear();}try{serverStream.Disconnect();serverStream.Dispose();}catch (Exception){}}}
}

服务创建和数据发送:

// 服务创建
NamedPipeServer namePipeServer = new NamedPipeServer("com.lois.pipe.gps.string");// 数据发送,格式:lon,lat,dir,speed,alt
if (namePipeServer != null)
{namePipeServer.sendCanData(string.Format("{0},{1},{2},{3},{4}", wgsP.Lng, wgsP.Lat, historyGeoData.Direction, historyGeoData.Speed, historyGeoData.Altitude));
}

http://chatgpt.dhexx.cn/article/QF257kDg.shtml

相关文章

GMap.NET入门详细教程【4】--------为控件添加事件,在鼠标单击时打点

GMap.NET入门 下载 GMap.NET&#xff0c;并在VS中添加GMap.NET控件初始化并加载一张地图添加标记点、线、多边形为控件添加事件&#xff0c;在鼠标单击时打点 快捷添加 选中窗体中的GMap控件&#xff0c;并查看内置事件 在这里&#xff0c;通过使用MouseDown和DoubleClick事…

GMap.net控件学习记录

主要参考网址 http://www.cnblogs.com/luxiaoxun/p/3802559.html http://www.cnblogs.com/luxiaoxun/p/3463250.html http://blog.csdn.net/onepiecehuiyu/article/details/19159565 GMap官方网址 http://greatmaps.codeplex.com/ WGS84&#xff0c;GCJ02&#xff0c;BD09坐标转…

Gmap使用说明,通过输入经纬度查询位置

由于本人对于Gmap的使用时间不长&#xff0c;有很多东西不是太熟悉&#xff0c;所以本人的代码有借鉴的部分&#xff0c;如有发现侵权&#xff0c;还请及时联系本人。 我目前已经基本实现了&#xff0c;地图的放大、缩小、平移的功能。完成了鼠标单击标点&#xff0c;输入经纬度…

GMap.net 自定义Marker

说明 自定义Marker部分内容来源于互联网&#xff0c;具体来源不记得了&#xff0c;若有人发现此处没注明出处&#xff0c;请海涵&#xff01; nuget包 GMapMarkerArrow using GMap.NET.WindowsForms; using System; using System.Collections.Generic; using System.Linq; usin…

C#基于开源地图GMap的开发示例

一.介绍 本示例程序是我在做项目前的探索示例。示例中测试了一些简单的功能&#xff0c;满足了我项目中的基本功能。更进一步的开发&#xff0c;有待继续研究。 二.项目源代码地址 源代码下载地址 三.项目讲解 1.引用GMap的dll文件 利用GMap开发&#xff0c;需要用到两个…

GMAP一款比对工具用于ALLHiC构建等位基因表

在ALLHiC使用过程中需要构建Allele.ctg.table&#xff0c;用于过滤多倍体基因组中因等位序列相似引起的HiC噪音的必要输入。官网提供了两种办法&#xff0c;一种是blastn&#xff0c;需要对草图基因组进行注释&#xff0c;这个过程挺麻烦的&#xff0c;在最下边看到了也可以使用…

Gmap使用心得分享C#-winform-Gmap

目录 一、Gmap库引用 1.下载Gmap引用库 2.Visual Studio添加项目引用 &#xff08;1&#xff09;打开项目后点击项目后添加引用 ​ &#xff08;2&#xff09;浏览本地库 &#xff08;3&#xff09;添加引用即可 二、Gmap使用流程 1.添加GmapControl 2.图…

基于GMap.Net的地图解决方案

一 地图的加载与显示 关于GMap的介绍与使用可以看我以前的文章: GMap.Net开发之在WinForm和WPF中使用GMap.Net地图插件 GMap.Net是.Net下一个地图控件,可以基于Http协议加载各个公司的地图,如Google,Bing,ArcGIS的,主要原理是通过解析各个公司的地图服务的URL,传入相应的…

Jersey框架常用注解3:媒体类型注解@Consumes和@Produces

Consumes 指定http请求的MIME类型&#xff0c;默认是*/*&#xff0c;表示任意的MIME类型。该注解的值是数组类型&#xff0c;支持多个MIME类型&#xff0c;可以使用MediaType来指定MIME类型。 Produces 指定http响应的MIME类型&#xff0c;默认是*/*&#xff0c;表示任意的M…

12.@RequestMapping中的consumes属性和produces属性

请求头header中很重要的两个参数:Accept:text/html只在响应中存在,表示当前请求希望服务器将来返回的数据类型是text/htmlContent-Type:application/json既可以出现在请求中,也可以出现在响应中,例如响应中代表服务器响应的是什么数据类型响应中response.setContentType("…

springmvc @RequestMapping注解中produces以及consumes属性的含义

http协议基础知识 首先需要了解什么叫MediaType&#xff08;媒体类型&#xff09;&#xff1f; 通俗来说&#xff0c;在http协议中&#xff0c;用来表示传输内容的格式就是MediaType&#xff0c;比如text/html&#xff0c;application/json等&#xff0c;其中text代表介质&am…

AJAX、异步和同步区别

1. 概念&#xff1a; ASynchronous JavaScript And XML (异步的JavaScript 和 XML) 异步和同步区别 2.Ajax作用&#xff1a; Ajax 是一种在无需重新加载整个网页的情况下&#xff0c;能够更新部分网页的技术。通过在后台与服务器进行少量数据交换&#xff0c;Ajax 可以使网页…

js异步与同步的区别

你应该知道&#xff0c;javascript语言是一门“单线程”的语言&#xff0c;不像java语言&#xff0c;类继承Thread再来个thread.start就可以开辟一个线程&#xff0c;所以&#xff0c;javascript就像一条流水线&#xff0c;仅仅是一条流水线而已&#xff0c;要么加工&#xff0…

同步调制和异步调制区别

在PWM控制电路中&#xff0c;载波频率 fc 和调制信号频率 fr 之比成为载波比&#xff0c;根据载波信号和信号波信号是否同步分为同步调制和异步调制。 1 什么是异步调制&#xff1f; 载波信号和调制信号不保持同步的方式称为异步调制&#xff0c;如下图所示&#xff0c;异步调…

同步和异步,区别

同步&#xff1a; 同步的思想是&#xff1a;所有的操作都做完&#xff0c;才返回给用户。这样用户在线等待的时间太长&#xff0c;给用户一种卡死了的感觉&#xff08;就是系统迁移中&#xff0c;点击了迁移&#xff0c;界面就不动了&#xff0c;但是程序还在执行&#xff0c;…

java同步和异步的区别_java中同步与异步区别是什么

一、同步与异步概念&#xff1a;(推荐&#xff1a;java视频教程) 1.同步&#xff1a;所有的操作都做完&#xff0c;才返回给用户。这样用户在线等待的时间太长&#xff0c;给用户一种卡死了的感觉(就是系统迁移中&#xff0c;点击了迁移&#xff0c;界面就不动了&#xff0c;但…

ajax什么是异步和同步,ajax异步和同步的区别

AJAX异步 打个比方吧,通常情况下,用户注册,那么用户首先得填写好表单,然后点提交,这样表单就会向服务发出一个请求,则服务器处理代码,如果用户存在,则返回一个信息。总之,就是所有的数据需要你点提交后,信息才会发送! 而AJAX就相当于是模拟了一个信息发送请求,你可…

java8拉姆达表达式对Object去重复

java8拉姆达表达式对Object去重复 public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {Map<Object, Boolean> seen new ConcurrentHashMap<>();return object -> seen.putIfAbsent(keyExtractor.a…

拉姆达表达式 filter与map的讲解

filter 根据条件过滤元素 map 获取(映射)每个元素,并对其进行操作 参考链接

sort()与拉姆达表达式

sort()与拉姆达表达式的结合 #include <iostream> #include <string> #include <vector> #include <ctime> #include <map> #include <utility> #include <algorithm>using std::cout; using std::endl; using std::string; using …