那些惊艳的 GIS 轮子

一、前言

GIS 涉及测绘、几何拓扑、人文社科等多方面的科学知识。在 .Net 平台下有着许多优秀的开源产品,比如:MapWindowSharpMapWorldWind等。而在这其中,CoordinateSharpNetTopologySuite是两款极其令人惊艳的中间开发组件产品。直到最近,我才遇到它们。

真的懊恼早没有人告诉我这些优秀的作品的存在。此前都一直在调用 c/c++的接口,虽说其效率很高,但最终产品还是 .Net 桌面的产品,其间各种相互调用后谁也不能保证效率的优势所在。并且出了问题还得反馈到底层开发组去重新修改编译发布一番。更别说调用 Python 的shapelygeopandas,或者 Java 的JTS Topology SuiteGeoTools等。正如聪明的读者想到的那样,可以将业务服务架构在这些优秀的产品之上。为此,有很长一段时间我都在研究wcfasp.net coreDjangoaspnet-microservicesdocker等。的确也出了一些效果和性能均令人满意的服务。但被告知后台业务将由 Java 组的人接手。于是,又开始了 Java 的研究,spring bootsparkhbase等等。也写了一些 Java 的服务端业务。但仍然避免不了高速实时数据处理,并且面向不同终端用户要计算不同需求的问题。最终还是会有一些定制化的业务留在了桌面端。这就像有了云计算后,还需要雾计算、边缘计算作为有益的补充。不可避免的,还得使用 .Net 的实现。

以上都是我用过的各个平台上的优秀产品,没有厚此薄彼的意思。这些也仅仅是为了具体的业务解决问题。下面特别地介绍一下CoordinateSharpNetTopologySuite。二者皆是可以跨平台的 .net core 产品。

二、CoordinateSharp

CoordinateSharp 是一个简单易用的进行地理坐标转换、空间天体计算的产品库。其强大与便捷之处我将以几个简单的小列子进行展示,仅抛砖引玉。

1.地理坐标转换

# 北京天安门广场的经纬度
CoordinateSharp.Coordinate.TryParse("N 39° 54' 27\" E 116° 23' 17\"",new DateTime(2019, 10, 1), out var c);
Console.WriteLine($"{c.Latitude.ToDouble()},{c.Longitude.ToDouble()}");//转换结果:39.9075,116.38805555555555

这里有一点令人疑惑的地方就是:为什么会有时间信息。这正是它的独到之处,不仅仅进行坐标转换,还带有计算日、月升落时间,位置等天体信息的能力:

Console.WriteLine($"{c.CelestialInfo.SunRise},{c.CelestialInfo.SunSet}");
# 10/1/2019 10:12:00 PM,10/1/2019 10:00:08 AM

由于时差原因,我们得加上 8 小时(东八区比格林尼治早 8 小时),于是结果变为10/2/2019 6:12:00 AM,10/1/2019 06:00:08 PM,日出时间变为第二天的早上了。日出减去 24 小时后为10/1/2019 6:12:00 AM。而日落仍然为10/1/2019 06:00:08 PM。查阅网上实时的信息:

日期 日出 日中 日落 昼长 天亮 天黑
2019 年 10 月 01 日 周二 06:10:11 12:04:10 17:58:08 11:47:57 05:43:19 18:25:00

基本一致,误差的原因由地球是椭球体、自转公转速率缓慢改变等引起。这个差别能够让人接受。

2.空间计算

计算球面距离

// 北京首都机场经纬度
var c1 = new CoordinateSharp.Coordinate(40.0760979329, 116.5953477768);
// 上海虹桥机场经纬度
var c2 = new CoordinateSharp.Coordinate(31.1982791377, 121.3356526703);
var d0 = new CoordinateSharp.Distance(c1, c2);
Console.WriteLine(d0.Kilometers);// 1074.0736250617888
Console.WriteLine(c1.ECEF);// 地球中心地球固定坐标(世界坐标系) -2188.311 km, 4369.881 km, 4084.559 km

而我们在网上查到的信息如下(注意,飞机真实飞行路线并非都是直线):

上海到北京的空中距离为 1084 公里,上海虹桥机场到首都机场飞行距离为 1160 公里

这与计算结果 1074.0736250617888 接近(没有办法排除各各家数据差异对距离计算结果产生的影响,比如,谷歌、百度、腾讯高德的坐标都不同,上述两个机场的位置坐标就是网上谷歌地球上取得的)。

此外,Coordinate 类有一个极其有用的方法void Move(double distance, double bearing, Shape shape)。其作用是计算往某个方向移动某个距离后的新坐标。

// 在椭球上向正北(方位角bearing正北为0)移动十公里,与c1原值比起来,经度基本没有变化
c1.Move(10000,0,Shape.Ellipsoid);
Console.WriteLine($"{c1.Latitude.ToDouble()},{c1.Longitude.ToDouble()}");// 40.16739008225999,116.60039000000003

由此看来,地理空间能力基本上解决了距离与位置的相互转换。更多功能欢迎探索https://github.com/Tronald/CoordinateSharp。去 star。

三、NetTopologySuite

NetTopologySuite 是一个快速可靠的 .Net GIS 解决方案。它提供了JTS Topology Suite所有功能的直接接口。JTS 是用于建模和平面几何计算,并且遵循Open GIS的 SQL 简单特性规范。而 NTS 基本上拥有这些能力,并且microsoft用其来为EF Core(This feature was added in EF Core 2.2.)提供空间计算能力。详情可以参看Spatial Data。可以说 JTS 是几何拓扑工具的 Java 实现,而 NTS 是 .NET 下的实现。

1.WKT 读写

var wkt = new WKTReader();
var gm = wkt.Read("POLYGON ((0 0,100 0, 100 100,0 100,0 0))");  //边长为100的正方形
Console.WriteLine(new WKTWriter().Write(gm));// POLYGON ((0 0, 100 0, 100 100, 0 100, 0 0))

2.几何图形计算

// 几何创建工厂(也可不使用工厂模式直接创建几何图形)
var gf = new GeometryFactory();
var pg3 = gf.CreatePolygon(new[]
{
    new Coordinate(612, 612),
    new Coordinate(144, 355),
    new Coordinate(165, 188),
    new Coordinate(277, 328),
    new Coordinate(612, 612)
});
var pg4 = gf.CreatePolygon(new[]
{
    new Coordinate(412, 612),
    new Coordinate(555, 455),
    new Coordinate(655, 188),
    new Coordinate(577, 328),
    new Coordinate(412, 612)
});

绿色是 pg3,金色是 pg4

求并集:var union = pg3.Union(pg4);

求交集:var intersection = pg3.Intersection(pg4);

求差集:var difference = pg3.Difference(pg4);
中间的连线是绘制时导致的,但是计算结果正确。我们查看其 WKT 描述为:MULTIPOLYGON (((478.68239179148486 538.78926215899912, 612 612, 499.14366946688551 516.32478247341942, 478.68239179148486 538.78926215899912)), ((478 498.4, 277 328, 165 188, 144 355, 460.37522887113056 528.73596970059953, 478 498.4)))的确是两个多边形。

其他能力,比如计算几何间距、面积、凸包、判断是否相交、是否覆盖等可查看项目的介绍或者 test 例子。详情访问https://github.com/NetTopologySuite/NetTopologySuite。去 star。

四、CoordinateSharp 与 NetTopologySuite

这么多优秀产品为何单独介绍 CoordinateSharp 与 NetTopologySuite?

假设有需求为画出某一城区的缓冲区,间距为 10km。这可怎么办?

在 NetTopologySuite 中直接提供缓冲区的计算函数public Geometry Buffer(double distance),效果也非常好:

红色为原始直线,按彩虹色依次相距为 10 的缓冲区

但是我们却忽略了一个重要的事情,NetTopologySuite 的计算的距离为平面坐标系下的欧氏距离。二维平面欧式距离的计算为Math.Sqrt(Math.Pow(x1-x2,2),Math.Pow(y1-y2,2)),直接用经纬度计算首都机场与虹桥机场的二维欧式距离为:10.06。而这个值显然对应着球面距离1074.07千米。考虑到随着维度的不同,两者之间的比例也并非是定值。最简单的例子就是,在赤道附近,一个经度差对应球面距离为 111.19 千米,而在 80° 纬度上则缩小到 19.31 千米,而在 90° 极点则几乎为 0 千米。

这时,我们就可以利用 CoordinateSharp 中点的移动功能,计算出给定球面距离对应的经纬度,然后利用移动前后的经纬度再计算欧式距离,得出的结果才较为准确。

还是以虹桥机场为例,绘制其半径为 100 千米的缓冲区:

// 对move进行简单的封装
public static double[] ConvertEarthDToPlaneXY(double lat, double lon, double distance, double bearing,
    Shape shape = Shape.Ellipsoid)
{
    var c0 = new CoordinateSharp.Coordinate(lat, lon);
    c0.Move(distance, bearing, shape);
    return new[] { c0.Latitude.ToDouble(), c0.Longitude.ToDouble() };
}

// 虹桥的位置
var hongqiao = new Coordinate(31.1982791377, 121.3356526703);
var hqPoint = gf.CreatePoint(hongqiao);
// 得出正西方向的100千米的位置hqMove
var hqMove = ConvertEarthDToPlaneXY(hongqiao.X, hongqiao.Y,100000, 270);
// 计算移动前后的欧式距离
var hqR = hongqiao.Distance(new Coordinate(hqMove[0], hqMove[1]);
// 计算buffer
var hqCircle = hqPoint.Buffer(hqR);
//验证得出的buffer上的点与虹桥机场的位置
hqCircle
    .Coordinates
    .ToList()
    .ForEach(t =>
    {
        var c1 = new CoordinateSharp.Coordinate(t.X, t.Y);
        var c2 = new CoordinateSharp.Coordinate(31.1982791377, 121.3356526703);
        var d0 = new CoordinateSharp.Distance(c1, c2, Shape.Sphere);
        Console.WriteLine(d0.Kilometers);
    });

验证结果如下:

116.66885608202652
116.05364820797979
114.28764035412392
111.60513634687186
108.37944785253909
105.09000981559511
102.2637861494519
100.38650671049055
99.79581077763879
100.59276661692931
102.61595683755391
105.4929026708211
108.73914573002186
111.85882184494989
114.41831613054764
116.0891677559819
116.66885608202652
116.0891677559819
114.41831613054846
111.85882184495108
108.73914573002347
105.4929026708211
102.61595683755391
100.59276661692915
99.7958107776412
100.38650671049055
102.26378614945223
105.09000981559511
108.37944785253909
111.60513634687305
114.28764035412605
116.05364820797979
116.66885608202652

大部分结果都超过了 100 千米,并且误差超过了 10 千米。比较妥善的方式就是计算多个方向的距离,然后取一个平均值。

public static double AverageDistance(double lat,double lon,double distance,int part)
{
    var seg = 360 / part;
    var rs = new List<double>();
    var raw = new Coordinate(lat, lon);
    for (var i = 0; i < 360; i += seg)
    {
        var move = ConvertEarthDToPlaneXY(lat, lon, distance, i);
        var r = raw.Distance(new Coordinate(move[0], move[1]));
        rs.Add(r);
    }
    return rs.Average();
}

上述缓冲区的距离计算改为:

// 取4个方向(0°、90°、180°和270°)对应的距离,然后求均值
var hqR = AverageDistance(hongqiao.X, hongqiao.Y, 100000,4);

得出的结果如下:

108.4796420377765
107.90879824241405
106.26991268291549
103.77978023046698
100.78401282732902
97.7268731801004
95.09732271673099
93.34698897092896
92.79099574532
93.52530908781738
95.401788528952
98.07519029469032
101.09498625442704
103.9991018274525
106.38288739908288
107.93950641121064
108.4796420377765
107.93950641121104
106.38288739908288
103.9991018274531
101.09498625442863
98.07519029469222
95.40178852895636
93.5253090878196
92.7909957453224
93.34698897093132
95.09732271673535
97.72687318010274
100.78401282733111
103.7797802304676
106.26991268291549
107.90879824241446
108.4796420377765

从结果中可以看出,误差控制在 10 千米之内。

上述计算的是一个点的缓冲区,如果是 LineString 或者 Polygon 的缓冲区,则尽可能的取其上不同的点进行距离转换后求取均值。

五、总结

总的来说,结合 CoordinateSharp 与 NetTopologySuite 可以进行许多有用的计算。但是误差也不可避免,特别是纬度较高的时候。

如果各位有其他更好的解决方案,希望提交评论。

原文地址:https://www.cnblogs.com/hsxian/p/11761571.html

时间: 2024-10-12 14:21:06

那些惊艳的 GIS 轮子的相关文章

中科燕园GIS外包团队(手机:13261043797,QQ:1216807928)arcgis10.3惊艳亮相

美国时间2014年12月10日,ArcGIS 10.3正式发布.这是Esri自2012年发布ArcGIS 10.2之后,历时两年的成果结晶.ArcGIS 10.3,隆重推出以用户为中心(Named User)的全新授权模式,超强的三维“内芯”,革新性的桌面GIS应用,可配置的服务器门户,即拿即用的Apps,更多应用开发新选择,数据开放新潮流,为构建新一代Web GIS应用提供了更强有力的核“芯”支持. 惊艳1:以用户为中心(Named User)的授权模式 ArcGIS 10.3采用了全新授权模

[ArcGIS 10.3重磅来袭]ArcGIS 10.3 惊艳登场,打造新一代Web GIS最强“芯”

今天是2015年的第一个工作日,咱来重磅出击一下. 美国时间2014年12月10日,ArcGIS 10.3正式发布.这是Esri自2012年发布ArcGIS 10.2之后,历时两年的成果结晶.ArcGIS 10.3,隆重推出以用户为中心(Named User)的全新授权模式,超强的三维"内芯",革新性的桌面GIS应用,可配置的服务器门户,即拿即用的Apps,更多应用开发新选择,数据开放新潮 流,为构建新一代Web GIS应用提供了更强有力的核"芯"支持. 现将Arc

ArcGIS 10.3 惊艳登场,打造新一代Web GIS最强“芯”

美国时间2014年12月10日,ArcGIS 10.3正式发布.这是Esri自2012年发布ArcGIS 10.2之后,历时两年的成果结晶.ArcGIS 10.3,隆重推出以用户为中心(Named User)的全新授权模式,超强的三维"内芯",革新性的桌面GIS应用,可配置的服务器门户,即拿即用的Apps,更多应用开发新选择,数据开放新潮流,为构建新一代Web GIS应用提供了更强有力的核"芯"支持. 惊艳1:以用户为中心(Named User)的授权模式 ArcG

从未如此惊艳!你好,SuperTextView

欢迎使用 SuperTextView,这篇文档将会向你展示如何使用这个控件来提高你构建项目的效率. SuperTextView 继承自 TextView,它能够大量的减少布局的复杂程度,并且使得一些常见的效果变得十分容易实现且高效.同时,它内置了动画驱动,你只需要合理编写Adjuster,然后startAnim()就可以看到预期的动画效果.它仅仅是一个控件,所以你可以不费吹灰之力的在你的项目中集成使用. 2 特点 你从此不必再为背景图编写和管理大量<shape>文件了. 重新优化的状态图功能使

《古墓丽影10》PC版重磅更新:DX12画质惊艳!

<古墓丽影10>PC版重磅更新:DX12画质惊艳! <古墓丽影>系列的最新作品<古墓丽影:崛起>已经上市一周有余,相信不少玩家都已经通关.但现在,官方给了PC版玩家一个再度通关的绝佳理由--画质大幅提升. 今天,<古墓丽影:崛起>开发商面向PC版推送了重磅更新,主要加入对于DX12和VXAO技术支持,从而使游戏光影.细节纹理表现获得全面增强,而且画面流畅性也有所改善. 官方公布的数据显示,测试机型配置为I7-2600,GTX970显卡.在DX11的环境下,游

人生,懂得相知,相惜包容之心不易。若灵犀一处,注定单一的风景,那就让生命于孤独中,开成一朵惊艳的花来,所有的资本,独倾城于自己!百度几下,你就知道,还得问百度

人生,懂得相知,相惜包容之心不易.若灵犀一处,注定单一的风景,那就让生命于孤独中,开成一朵惊艳的花来,所有的资本,独倾城于自己! ————题记 又是下雨的天气,青石板的湿气寒生,缝隙边的小草,漫步一春,一夏,一秋,于这冬天,仿佛还在执意某个角落,安定一个归属,定要等到霜雪满天,才肯凋谢! 若可,我愿是丁香般的女子,无须为了谁而忧怨,更无需丈量光阴给予的深浅,只管停泊江南的一席之地,为自己开一扇幽窗,与书共知己.风来且沐浴,月倚枕边书:雨临相对盏,醉赋宋唐风:再植一盆盆的兰草,便可举杯邀月兰生慧,

20款惊艳的矢量花纹素材

1.三款时尚花卉花纹矢量图免费下载 查看内容>>下载>> 2.光芒四射的金色花纹背景矢量图 查看内容>>下载>> 3.怀旧风格的花纹边框矢量图 查看内容>> 下载>> 4.四款时尚欧式边框矢量图 查看内容>>  下载>> 5.三款漂亮的紫藤花边边框矢量图 查看内容>> 下载>> 6.一款精美的心形花边素材矢量图 查看内容>> 下载>> 7.两款彩色线条素材矢量图

算法之美---100幅由程序生成的图像,总有一幅让你感到惊艳[下]

来看看算法能生成什么样的图像,继续发余下的50幅.这50幅图像中大部分与分形有关,算法难度要比前50幅大一些,当然其视觉效果会更为惊艳.所有图像均由我开发的软件“Why数学图像生成工具”生成. (51)Sharp Edges (52)Binary Flash (53)Mandelbrot 1 (54)Mandelbrot By Martin (55)Mandelbrot By Kasten (56)Mandelbrot By Lehman (57)Julia Sets 1 (58)Julia S

惊艳的cygwin——Windows下的Linux命令行环境的配置和使用

http://www.tuicool.com/articles/2MramqI 时间 2014-07-29 09:28:36  点滴之间 聚沙成金 原文  http://www.path8.net/tn/archives/6021 主题 CygwinLinux命令 本文内容遵从 CC版权协议 , 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明网址: http://oldratlee.com/post/2012-12-22/stunning-cygwin N年前倒腾过一次