S2算法应用
需求:计算不同区域范围,X公里半径内实体店或场站覆盖率。
实现思路:
- 为了便于理解,将地球看成一个基于经纬度线的坐标系。将经度和纬度看成二维坐标系中的两个纬度,横轴表示经度[-180o, 0o),(0o, 180o],纵轴表示纬度[-90o, 0o),(0o, 90o]。
- 以最小纬度和经度对应坐标为第一个六角形中心点,在经度方向循环计算六角形各顶点(顶点开始,顺时针,命名:Point1,Point2,Point3,Point4,Point5,Point6)及中心点(Point0)坐标,直至六角形中心点经度大于等于最大经度。 存储六角形标记为(0,0),(0,1),(0,2) ......., 表示六边形位于第0行第N列
- 第一行计算完成后,开始计算第2行,如下图,第2行(奇数行), 除第1个和最后一个点作特殊处理外,其它点的 Point3、Point4、Point5是重叠的,注意坐标的处理,否则会出现偏差
 
- 在维度方向上按上一步循环。完成整个区域范围内六角边分割,注意:为了快速定位,还需计算出每个六角形中心点对应的Geohash,根据半径不一致,可选择不同的Geohash级别
- 根据场站经纬度计算出30级 Cell ID 值 及 Geohash 码
- 根据 Geohash 码找出附近的六角形,通过六顶点坐标 构造 IRegion, 判断场站是否包含在六边形内,如果不包含,再次计算出当前Geohash码周边8个Geohash框,再次计算
- 至此完成此区域内场站命中的六角形。
关键代码
- 根据中心点坐标、边长、偏差角度(中心点至顶点开始)计算下一个点坐标
- public const double Ea = ; // 赤道半径(米) 
 public const double Eb = ; // 极半径 (米) /// <summary>
 ///
 /// </summary>
 /// <param name="lat"></param>
 /// <param name="lng"></param>
 /// <param name="distance"></param>
 /// <param name="angle"></param>
 /// <returns></returns>
 public static Point GetPoint(double lat, double lng, double distance, double angle)
 { double dx = distance * * Math.Sin(angle * Math.PI / 180.0);
 double dy = distance * * Math.Cos(angle * Math.PI / 180.0); double ec = Eb + (Ea - Eb) * (90.0 - lat) / 90.0;
 double ed = ec * Math.Cos(lat * Math.PI / 180.0); double newLon = (dx / ed + lng * Math.PI / 180.0) * 180.0 / Math.PI;
 double newLat = (dy / ec + lat * Math.PI / 180.0) * 180.0 / Math.PI; return new Point(newLat, newLon);
 }
- 计算场站所属六边形
- /// <summary> 
 ///
 /// </summary>
 /// <param name="destRows"></param>
 /// <param name="cell"></param>
 /// <param name="level"></param>
 /// <param name="staid"></param>
 /// <param name="hashMap"></param>
 /// <param name="geohashValue"></param>
 /// <returns></returns>
 private string GetPgID(DataTable dest, S2Cell cell,string geohashValue)
 {
 //先找当前geohash4的值
 string pgID = this.GetPGIDByHash(dest, cell, geohashValue);
 if (string.IsNullOrEmpty(pgID) == false)
 return pgID; //当前hash未命中时,找相邻8格
 List<string> hashLst = GeoHashService.Default.GetGeoHashExpand(geohashValue);
 foreach (string ghValue in hashLst)
 {
 pgID = this.GetPGIDByHash(dest, cell, ghValue);
 if (string.IsNullOrEmpty(pgID) == false)
 return pgID;
 } return string.Empty;
 } /// <summary>
 ///
 /// </summary>
 /// <param name="dest"></param>
 /// <param name="cell"></param>
 /// <param name="geohashValue"></param>
 /// <returns></returns>
 private string GetPGIDByHash(DataTable dest, S2Cell cell, string geohashValue)
 {
 DataRow[] destRows = dest.Select(string.Format("{0} = '{1}'", M_GEOHASH, geohashValue)); //城市均分的网格 foreach (DataRow dRow in destRows)
 {
 string pgID = Convert.ToString(dRow["ID"]);
 IS2Region cells = this.BuildPolygon(dRow); if (cells.Contains(cell) == true)
 {
 return pgID;
 }
 } return string.Empty;
 } /// <summary>
 /// 构造容器
 /// </summary>
 /// <param name="row"></param>
 /// <returns></returns>
 private IS2Region BuildPolygon(DataRow row)
 {
 List<S2Point> lst = new List<S2Point>();
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat1"]), Convert.ToDouble(row["lng1"])));
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat2"]), Convert.ToDouble(row["lng2"])));
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat3"]), Convert.ToDouble(row["lng3"])));
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat4"]), Convert.ToDouble(row["lng4"])));
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat5"]), Convert.ToDouble(row["lng5"])));
 lst.Add(this.GetPoint(Convert.ToDouble(row["lat6"]), Convert.ToDouble(row["lng6"]))); S2Loop loop = new S2Loop(lst);
 loop.Normalize();
 return loop;
 }
示例效果
参考资料
S2算法应用的更多相关文章
- C#实现Google S2算法
		S2其实是来自几何数学中的一个数学符号 S²,它表示的是单位球.S2 这个库其实是被设计用来解决球面上各种几何问题的.值得提的一点是,除去 golang 官方 repo 里面的 geo/s2 完成度目 ... 
- 高效的多维空间点索引算法 — Geohash 和 Google S2
		原文地址:https://www.jianshu.com/p/7332dcb978b2 引子 每天我们晚上加班回家,可能都会用到滴滴或者共享单车.打开 app 会看到如下的界面: app ... 
- 空间数据库系列二:空间索引S2与Z3分析对比
		S2与Z3对比分析 1. S2 2. Geohash 3. Geomesa Z3 4. S2对比geohash 4.1. geohash存在的问题 4.2. S2优势 4.3. 实际对比例子 5. 测 ... 
- [luoguP1578] 奶牛浴场(DP)
		传送门 O(s2)算法 详见论文 王知昆--浅谈用极大化思想解决最大子矩形问题 我就复制你能把我怎么样QAQ #include <cstdio> #include <iostream ... 
- 深入解密来自未来的缓存-Caffeine
		1.前言 读这篇文章之前希望你能好好的阅读: 你应该知道的缓存进化史 和 如何优雅的设计和使用缓存? .这两篇文章主要从一些实战上面去介绍如何去使用缓存.在这两篇文章中我都比较推荐Caffeine这款 ... 
- 基于 Google-S2 的地理相册服务实现及应用
		马蜂窝技术原创内容,更多干货请关注公众号:mfwtech 随着智能手机存储容量的增大,以及相册备份技术的普及,我们可以随时随地用手机影像记录生活,在手机中存储几千张甚至上万张照片已经是很常见的事情.但 ... 
- 分布式一致性算法--Paxos
		Paxos算法是莱斯利·兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法.Paxos算法解决的问题是一个分布式系统如何就某个值(决议)达成一致.在工程实践意义上来说, ... 
- C#实现Levenshtein distance最小编辑距离算法
		Levenshtein distance,中文名为最小编辑距离,其目的是找出两个字符串之间需要改动多少个字符后变成一致.该算法使用了动态规划的算法策略,该问题具备最优子结构,最小编辑距离包含子最小编辑 ... 
- Hihocoder 太阁最新面经算法竞赛18
		Hihocoder 太阁最新面经算法竞赛18 source: https://hihocoder.com/contest/hihointerview27/problems 题目1 : Big Plus ... 
随机推荐
- Bug02_MyBatis_org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
			我出现问题的原因是: 映射xml文件名写错了. 查资料,可以有以下解决办法 按以下步骤一一执行: 1:检查xml文件所在的package名称是否和interface对应的package名称一一对应 2 ... 
- codeforce 839A  Arya and Bran(水题)
			Bran and his older sister Arya are from the same house. Bran like candies so much, so Arya is going ... 
- socket 映射服务器--(可处理多客户端连接(fork),显示退出信息)
			server #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket ... 
- java网络编程ServerSocket类 和Socket类的常用构造方法及其方法
			Socket类Socket(InetAddress address, int port) 创建一个流套接字并将其连接到指定 IP 地址的指定端口号.Socket(String host, int po ... 
- Python学习笔记第六周
			目录 一.基础概念 面向对象编程 1.面向对象的几个核心特点 1.class类 2.object对象 3.encapsulation封装 4.inheritance继承 5.polymorphism多 ... 
- 20165228 2017-2018-2 《Java程序设计》第5周学习总结
			20165228 2017-2018-2 <Java程序设计>第5周学习总结 教材学习内容总结 内部类和匿名类 通过throw关键字抛出异常对象,终止方法的继续执行 使用try-catch ... 
- 【c++基础】static修饰的函数作用与意义
			static修饰的函数作用与意义 static修饰的函数叫做静态函数,静态函数有两种,根据其出现的地方来分类: 如果这个静态函数出现在类里,那么它是一个静态成员函数: 静态成员函数的作用在于:调用这个 ... 
- pytorch使用tensorboardX进行loss可视化
			最近pytorch出了visdom,也没有怎么去研究它,主要是觉得tensorboardX已经够用,而且用起来也十分的简单 pip install tensorboardX 然后在代码里导入 from ... 
- POJO,JaveBean,VO,DTO
			POJO - POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称. 使用POJO名称是为了避免和EJ ... 
- angular file change
			AngularJs: How to check for changes in file input fields? <input type="file" onchange=& ... 
 
			
		