GIS 涉及测绘、几何拓扑、人文社科等多方面的科学知识。在 .Net 平台下有着许多优秀的开源产品,比如:MapWindow、SharpMap、WorldWind等。而在这其中,CoordinateSharp与NetTopologySuite是两款极其令人惊艳的中间开发组件产品。直到最近,我才遇到它们。
真的懊恼早没有人告诉我这些优秀的作品的存在。此前都一直在调用 c/c++的接口,虽说其效率很高,但最终产品还是 .Net 桌面的产品,其间各种相互调用后谁也不能保证效率的优势所在。并且出了问题还得反馈到底层开发组去重新修改编译发布一番。更别说调用 Python 的shapely、geopandas,或者 Java 的JTS Topology Suite、GeoTools等。正如聪明的读者想到的那样,可以将业务服务架构在这些优秀的产品之上。为此,有很长一段时间我都在研究wcf、asp.net core、Django、aspnet-microservices和docker等。的确也出了一些效果和性能均令人满意的服务。但被告知后台业务将由 Java 组的人接手。于是,又开始了 Java 的研究,spring boot、spark、hbase等等。也写了一些 Java 的服务端业务。但仍然避免不了高速实时数据处理,并且面向不同终端用户要计算不同需求的问题。最终还是会有一些定制化的业务留在了桌面端。这就像有了云计算后,还需要雾计算、边缘计算作为有益的补充。不可避免的,还得使用 .Net 的实现。
以上都是我用过的各个平台上的优秀产品,没有厚此薄彼的意思。这些也仅仅是为了具体的业务解决问题。下面特别地介绍一下CoordinateSharp与NetTopologySuite。二者皆是可以跨平台的 .net core 产品。
二、CoordinateSharpCoordinateSharp 是一个简单易用的进行地理坐标转换、空间天体计算的产品库。其强大与便捷之处我将以几个简单的小列子进行展示,仅抛砖引玉。
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。
三、NetTopologySuiteNetTopologySuite 是一个快速可靠的 .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))