当前位置:   article > 正文

Java实现Google的S2算法工具类_google 矩形工具类

google 矩形工具类

WGS84坐标系 GCJ02坐标系 BD09坐标系的各种转换

WGS84坐标系 GCJ02坐标系 BD09坐标系的各种转换 Google S2 经纬度 转 CellId 经纬度 转 cellToken CellId 转 经纬度 判断当前cellId的level * 获取任意形状内所有S2块 * 可以用于区域内目标检索,根据cellid建立索引,查询区域内cellid in (list)的区域 S2计算点距离 计算地球上某个点是否在矩形区域内 计算点s2是否在圆中心为s1半径为capHeight的圆形区域内 判断点是否在任意形状内 计算两个区域是否有交集 求不同等级S2块包含的S2子块

S2 Demo

Java实现Google的S2算法工具类GoogleS2GoogleS2GoogleS2-Java文档类资源-CSDN下载

level (等级)min area(最小面积)max area(最大面积)average area(平均面积)units(单位)Random cell 1 (UK)() min edge length(随机单元1 (UK)最小边长度)Random cell 1 (UK) max edge length(随机单元格1 (UK)最大边长度)Random cell 2 (US) min edge length(随机单元2 (US)最小边长度)Random cell 2 (US) max edge length(随机单元格2(美国)最大边长度)Number of cells(单元格数)
085011012.1985011012.1985011012.19km27842 km7842 km7842 km7842 km6
121252753.0521252753.0521252753.05km23921 km5004 km3921 km5004 km24
24919708.236026521.165313188.26km21825 km2489 km1825 km2489 km96
31055377.481646455.51328297.07km2840 km1167 km1130 km1310 km384
4231564.06413918.15332074.27km2432 km609 km579 km636 km1536
553798.67104297.9183018.57km2210 km298 km287 km315 km6K
612948.8126113.320754.64km2108 km151 km143 km156 km24K
73175.446529.095188.66km254 km76 km72 km78 km98K
8786.21632.451297.17km227 km38 km36 km39 km393K
9195.59408.12324.29km214 km19 km18 km20 km1573K
1048.78102.0381.07km27 km9 km9 km10 km6M
1112.1825.5120.27km23 km5 km4 km5 km25M
123.046.385.07km21699 m2 km2 km2 km100M
130.761.591.27km2850 m1185 m1123 m1225 m402M
140.190.40.32km2425 m593 m562 m613 m1610M
1547520.399638.9379172.67m2212 m296 m281 m306 m6B
1611880.0824909.7319793.17m2106 m148 m140 m153 m25B
172970.026227.434948.29m253 m74 m70 m77 m103B
18742.51556.861237.07m227 m37 m35 m38 m412B
19185.63389.21309.27m213 m19 m18 m19 m1649B
2046.4197.377.32m27 m9 m9 m10 m7T
2111.624.3319.33m23 m5 m4 m5 m26T
222.96.084.83m2166 cm2 m2 m2 m105T
230.731.521.21m283 cm116 cm110 cm120 cm422T
240.180.380.3m241 cm58 cm55 cm60 cm1689T
25453.19950.23755.05cm221 cm29 cm27 cm30 cm7.00E+15
26113.3237.56188.76cm210 cm14 cm14 cm15 cm2.70E+16
2728.3259.3947.19cm25 cm7 cm7 cm7 cm1.08E+17
287.0814.8511.8cm22 cm4 cm3 cm4 cm4.32E+17
291.773.712.95cm212 mm18 mm17 mm18 mm1.73E+18
300.440.930.74cm26 mm9 mm8 mm9 mm7.00E+18
  1. package com.zz.meridian.utils.googleS2;
  2. /**
  3. * @author tiger
  4. * GPS位置信息接下来说下坐标系。目前主要有三种地理坐标系,如下:
  5. * 1、WGS84坐标系:即地球坐标系(World Geodetic System),国际上通用的坐标系。
  6. * 设备包含的GPS芯片或者北斗芯片获取的经纬度一般都是为WGS84地理坐标系,目前谷歌地图采用的是WGS84坐标系(中国范围除外)。
  7. * 2、GCJ02坐标系:即火星坐标系,国测局坐标系。是由中国国家测绘局制定。由WGS84坐标系经加密后的坐标系。谷歌中国和搜搜中国采用的GCJ02地理坐标系。
  8. * 3、BD09坐标系:百度坐标系,GCJ02坐标系经加密后的坐标系。
  9. * 4、其他(搜狗坐标系,图吧坐标系等)。大概率也是再GCJ02坐标系基础上加密生成的
  10. */
  11. public class PointS2Transform {
  12. public static double x_PI = 3.14159265358979324 * 3000.0 / 180.0;
  13. public static double PI = 3.1415926535897932384626;
  14. public static double a = 6378245.0;
  15. public static double ee = 0.00669342162296594323;
  16. /**
  17. * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
  18. * 即 百度 转 谷歌、高德
  19. *
  20. * @param bd_lon
  21. * @param bd_lat
  22. * @returns {*[]}
  23. */
  24. public static PointS2 bd09togcj02(double bd_lon, double bd_lat) {
  25. double x = bd_lon - 0.0065;
  26. double y = bd_lat - 0.006;
  27. double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
  28. double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
  29. double gg_lng = z * Math.cos(theta);
  30. double gg_lat = z * Math.sin(theta);
  31. PointS2 point = new PointS2(gg_lat, gg_lng);
  32. return point;
  33. }
  34. /**
  35. * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
  36. * 即谷歌、高德 转 百度
  37. *
  38. * @param lng
  39. * @param lat
  40. * @returns {*[]}
  41. */
  42. public static PointS2 gcj02tobd09(double lng, double lat) {
  43. double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
  44. double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
  45. double bd_lng = z * Math.cos(theta) + 0.0065;
  46. double bd_lat = z * Math.sin(theta) + 0.006;
  47. PointS2 point = new PointS2(bd_lat, bd_lng);
  48. return point;
  49. }
  50. ;
  51. /**
  52. * WGS84转GCj02
  53. *
  54. * @param lng
  55. * @param lat
  56. * @returns {*[]}
  57. */
  58. public static PointS2 wgs84togcj02(double lng, double lat) {
  59. double dlat = transformlat(lng - 105.0, lat - 35.0);
  60. double dlng = transformlng(lng - 105.0, lat - 35.0);
  61. double radlat = lat / 180.0 * PI;
  62. double magic = Math.sin(radlat);
  63. magic = 1 - ee * magic * magic;
  64. double sqrtmagic = Math.sqrt(magic);
  65. dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
  66. dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
  67. double mglat = lat + dlat;
  68. double mglng = lng + dlng;
  69. PointS2 point = new PointS2(mglat, mglng);
  70. return point;
  71. }
  72. /**
  73. * 84 to ⽕星坐标系 (GCJ-02) 是否离开了中国版
  74. *
  75. * @param lat
  76. * @param lon
  77. */
  78. public static PointS2 gps84_To_Gcj02(double lat, double lon) {
  79. if (outOfChina(lat, lon)) {
  80. return null;
  81. }
  82. double dLat = transformLat(lon - 105.0, lat - 35.0);
  83. double dLon = transformLon(lon - 105.0, lat - 35.0);
  84. double radLat = lat / 180.0 * PI;
  85. double magic = Math.sin(radLat);
  86. magic = 1 - ee * magic * magic;
  87. double sqrtMagic = Math.sqrt(magic);
  88. dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  89. dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
  90. double mgLat = lat + dLat;
  91. double mgLon = lon + dLon;
  92. return new PointS2(mgLat, mgLon);
  93. }
  94. /**
  95. * ⽕星坐标系 GCJ02 转换为 WGS84
  96. *
  97. * @param lng
  98. * @param lat
  99. * @returns {*[]}
  100. */
  101. public static PointS2 gcj02towgs84(double lng, double lat) {
  102. double dlat = transformlat(lng - 105.0, lat - 35.0);
  103. double dlng = transformlng(lng - 105.0, lat - 35.0);
  104. double radlat = lat / 180.0 * PI;
  105. double magic = Math.sin(radlat);
  106. magic = 1 - ee * magic * magic;
  107. double sqrtmagic = Math.sqrt(magic);
  108. dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
  109. dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
  110. double mglat = lat + dlat;
  111. double mglng = lng + dlng;
  112. PointS2 point = new PointS2(mglat, mglng);
  113. return point;
  114. }
  115. /**
  116. * ⽕星坐标系 GCJ02 转换为 WGS84 是否离开了中国版
  117. * @param lon * @param lat * @return
  118. */
  119. public static PointS2 gcj_To_Gps84(double lat, double lon) {
  120. PointS2 gps = transform(lat, lon);
  121. double lontitude = lon * 2 - gps.getLng();
  122. double latitude = lat * 2 - gps.getLat();
  123. return new PointS2(latitude, lontitude);
  124. }
  125. /**
  126. * 将 GCJ-02 坐标转换成 BD-09 坐标
  127. * @param gg_lat
  128. * @param gg_lon
  129. */
  130. public static PointS2 gcj02_To_Bd09(double gg_lat, double gg_lon) {
  131. double x = gg_lon, y = gg_lat;
  132. double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * PI);
  133. double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * PI);
  134. double bd_lon = z * Math.cos(theta) + 0.0065;
  135. double bd_lat = z * Math.sin(theta) + 0.006;
  136. return new PointS2(bd_lat, bd_lon);
  137. }
  138. /**
  139. * 将 BD-09 坐标转换成GCJ-02 坐标
  140. * bd_lat * @param bd_lon * @return
  141. */
  142. public static PointS2 bd09_To_Gcj02(double bd_lat, double bd_lon) {
  143. double x = bd_lon - 0.0065;
  144. double y = bd_lat - 0.006;
  145. double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * PI);
  146. double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * PI);
  147. double gg_lon = z * Math.cos(theta);
  148. double gg_lat = z * Math.sin(theta);
  149. return new PointS2(gg_lat, gg_lon);
  150. }
  151. /**
  152. * (BD-09)-->84
  153. *
  154. * @param bd_lat
  155. * @param bd_lon
  156. * @return
  157. */
  158. public static PointS2 bd09_To_Gps84(double bd_lat, double bd_lon) {
  159. PointS2 gcj02 = bd09_To_Gcj02(bd_lat, bd_lon);
  160. PointS2 map84 = gcj_To_Gps84(gcj02.getLat(),
  161. gcj02.getLng());
  162. return map84;
  163. }
  164. /**
  165. * is or not outOfChina
  166. * 是否离开了中国
  167. * @param lat
  168. * @param lon
  169. * @return
  170. */
  171. public static boolean outOfChina(double lat, double lon) {
  172. if (lon < 72.004 || lon > 137.8347)
  173. return true;
  174. if (lat < 0.8293 || lat > 55.8271)
  175. return true;
  176. return false;
  177. }
  178. private static double transformlat(double lng, double lat) {
  179. double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
  180. ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
  181. ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
  182. ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
  183. return ret;
  184. }
  185. private static double transformlng(double lng, double lat) {
  186. double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
  187. ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
  188. ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
  189. ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
  190. return ret;
  191. }
  192. public static PointS2 transform(double lat, double lon) {
  193. if (outOfChina(lat, lon)) {
  194. return new PointS2(lat, lon);
  195. }
  196. double dLat = transformLat(lon - 105.0, lat - 35.0);
  197. double dLon = transformLon(lon - 105.0, lat - 35.0);
  198. double radLat = lat / 180.0 * PI;
  199. double magic = Math.sin(radLat);
  200. magic = 1 - ee * magic * magic;
  201. double sqrtMagic = Math.sqrt(magic);
  202. dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
  203. dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
  204. double mgLat = lat + dLat;
  205. double mgLon = lon + dLon;
  206. return new PointS2(mgLat, mgLon);
  207. }
  208. public static double transformLat(double x, double y) {
  209. double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
  210. + 0.2 * Math.sqrt(Math.abs(x));
  211. ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
  212. ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
  213. ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
  214. return ret;
  215. }
  216. public static double transformLon(double x, double y) {
  217. double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
  218. * Math.sqrt(Math.abs(x));
  219. ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
  220. ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
  221. ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0
  222. * PI)) * 2.0 / 3.0;
  223. return ret;
  224. }
  225. }

  1. package com.zz.meridian.utils.googleS2;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class PointS2 {
  9. double lat;
  10. double lng;
  11. }

  1. package com.zz.meridian.utils.googleS2;
  2. import com.google.common.collect.Lists;
  3. import com.google.common.geometry.*;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import java.util.stream.Collectors;
  7. /**
  8. * @author tiger
  9. * 必须使用-S2使用的是WGS84坐标
  10. * 如果你获得的是WGS84坐标-百度或者高德的地理坐标,请将其转换为GPS-WGS84坐标
  11. * 由于google s2默认使用gps坐标系,在国内无法使用,需要转换为国内的gcj坐标或者bd09坐标
  12. * 主要包含3类方法:
  13. * getS2RegionByXXX
  14. * 获取给定经纬度坐标对应的S2Region,该region可用于获取cellId,或用于判断包含关系
  15. * getCellIdList
  16. * 获取给定region的cellId,并通过childrenCellId方法控制其严格遵守minLevel
  17. * contains
  18. * 对于指定S2Region,判断经纬度或CellToken是否在其范围内
  19. */
  20. /*
  21. <dependency>
  22. <groupId>io.sgr</groupId>
  23. <artifactId>s2-geometry-library-java</artifactId>
  24. <version>1.0.0</version>
  25. </dependency>
  26. */
  27. public class GoogleS2 {
  28. /**
  29. * 经纬度 转 S2CellId
  30. *
  31. * @param lat 维度
  32. * @param lng 经度
  33. * @param currentLevel level选择级别
  34. */
  35. public static S2CellId latLonToS2LatLng(double lat, double lng, int currentLevel) {
  36. S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);
  37. S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);
  38. return cellId;
  39. }
  40. /**
  41. * 经纬度 转 CellId
  42. *
  43. * @param lat 维度
  44. * @param lng 经度
  45. * @param currentLevel level选择级别
  46. */
  47. public static Long latLonToCellId(double lat, double lng, int currentLevel) {
  48. S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);
  49. S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);
  50. return cellId.id();
  51. }
  52. /**
  53. * 经纬度 转 cellToken
  54. *
  55. * @param lat 维度
  56. * @param lng 经度
  57. * @param currentLevel level选择级别
  58. */
  59. public static String latLonToCellToken(double lat, double lng, int currentLevel) {
  60. try {
  61. S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);
  62. S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);
  63. return cellId.toToken();
  64. } catch (Exception e) {
  65. e.printStackTrace();
  66. return null;
  67. }
  68. }
  69. /**
  70. * CellId 转 经纬度
  71. *
  72. * @param cellId 是 S2CellId.id();
  73. * @return
  74. */
  75. public static PointS2 cellIdToLatLon(Long cellId) {
  76. S2LatLng s2LatLng = new S2CellId(cellId).toLatLng();
  77. double lat = s2LatLng.latDegrees();
  78. double lng = s2LatLng.lngDegrees();
  79. return new PointS2(lat, lng);
  80. }
  81. /**
  82. * cellToken 转 经纬度
  83. *
  84. * @param cellToken
  85. * @return
  86. */
  87. public static PointS2 cellTokenToLatLon(String cellToken) {
  88. S2LatLng latLng = new S2LatLng(S2CellId.fromToken(cellToken).toPoint());
  89. return new PointS2(latLng.latDegrees(), latLng.lngDegrees());
  90. }
  91. /**
  92. * 判断region是否包含指定经纬度坐标
  93. *
  94. * @param region
  95. * @param lat
  96. * @param lon
  97. * @return
  98. */
  99. public static boolean contains(S2Region region, double lat, double lon) {
  100. S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lon);
  101. try {
  102. boolean contains = region.contains(new S2Cell(s2LatLng));
  103. return contains;
  104. } catch (NullPointerException e) {
  105. e.printStackTrace();
  106. return false;
  107. }
  108. }
  109. /**
  110. * 判断当前cellId的level
  111. *
  112. * @param cellId
  113. * @return
  114. */
  115. public static int getLevel(long cellId) {
  116. int n = 0;
  117. while (cellId % 2 == 0) {
  118. cellId = cellId / 2;
  119. n++;
  120. }
  121. return 30 - n / 2;
  122. }
  123. /**
  124. * 获取任意形状内所有S2块
  125. * 可以用于区域内目标检索,根据cellid建立索引,查询区域内cellid in (list)的区域
  126. *
  127. * @param vertices 形成多边形的点集合
  128. * @return
  129. */
  130. private static List<Long> vertices(List<PointS2> vertices) {
  131. //因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下
  132. List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());
  133. S2Loop s2Loop = new S2Loop(collect);
  134. S2Polygon cap = new S2Polygon(s2Loop); //创建多边形
  135. //S2Region cap 任意区域
  136. S2RegionCoverer coverer = new S2RegionCoverer();
  137. //最小格子和最大格子,总格子数量
  138. coverer.setMinLevel(7);//设置最小级别
  139. coverer.setMaxLevel(15);//设置最大级别
  140. coverer.setMaxCells(500);//设置最大Cell
  141. List<S2CellId> list = coverer.getCovering(cap).cellIds();
  142. // for (S2CellId s : list) {
  143. // System.out.println(s.id());
  144. // }
  145. return list.stream().map(S2CellId::id).collect(Collectors.toList());
  146. }
  147. /**
  148. * S2计算距离
  149. *
  150. * @param s1 点1的经度 纬度
  151. * @param s2 点2的经度 纬度
  152. * @return
  153. */
  154. public static double distance(PointS2 s1, PointS2 s2) {
  155. S2LatLng startS2 = S2LatLng.fromDegrees(s1.getLat(), s1.getLng());
  156. S2LatLng endS2 = S2LatLng.fromDegrees(s2.getLat(), s2.getLng());
  157. double distance = startS2.getEarthDistance(endS2);
  158. return distance;
  159. }
  160. /**
  161. * 计算地球上某个点是否在矩形区域内
  162. * 矩形的左下角点和矩形的右上角点通过纬度来判断,高低不然算不出来
  163. * @param s1 生成矩形的经纬度s1
  164. * @param s2 生成矩形的经纬度s2
  165. * @param s3 判断s3点是否在上面s1和s2的矩形中
  166. * @return
  167. */
  168. public static boolean pointRectangleArea(PointS2 s1, PointS2 s2, int desLevel, PointS2 s3) {
  169. S2LatLngRect rect = null;
  170. if (s1.getLat() > s2.getLat()) {
  171. //两个点可以经纬度-构建S2矩形
  172. rect = new S2LatLngRect(
  173. S2LatLng.fromDegrees(s2.getLat(), s2.getLng()),
  174. S2LatLng.fromDegrees(s1.getLat(), s1.getLng()));
  175. } else {
  176. //两个点可以经纬度-构建S2矩形
  177. rect = new S2LatLngRect(
  178. S2LatLng.fromDegrees(s1.getLat(), s1.getLng()),
  179. S2LatLng.fromDegrees(s2.getLat(), s2.getLng()));
  180. }
  181. //设置矩形的大小
  182. S2RegionCoverer coverer = new S2RegionCoverer();
  183. //设置cell
  184. coverer.setMinLevel(7);
  185. coverer.setMaxLevel(15);
  186. coverer.setMaxCells(500);
  187. S2CellUnion covering = coverer.getCovering(rect);
  188. S2LatLng s2LatLng = S2LatLng.fromDegrees(s3.getLat(), s3.getLng());
  189. return covering.contains(s2LatLng.toPoint());
  190. }
  191. /**
  192. * 计算点s2是否在圆中心为s1半径为capHeight的圆形区域内
  193. *
  194. * @param s1
  195. * @param capHeight
  196. * @param s2
  197. * @return
  198. */
  199. public static boolean pointGardenArea(PointS2 s1, double capHeight, PointS2 s2) {
  200. S2LatLng s2LatLng = S2LatLng.fromDegrees(s1.getLat(), s1.getLng());
  201. S2Cap cap = S2Cap.fromAxisHeight(s2LatLng.toPoint(), capHeight);
  202. S2LatLng s2LatLng2 = S2LatLng.fromDegrees(s2.getLat(), s2.getLng());
  203. boolean contains = cap.contains(s2LatLng2.toPoint());
  204. return contains;
  205. }
  206. /**
  207. * 判断点是否在任意形状内
  208. *
  209. * @param vertices 形成多边形的点集合
  210. * @param s 判断的点
  211. * @return
  212. */
  213. public static boolean pointPolygonArea(List<PointS2> vertices, PointS2 s) {
  214. //因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下
  215. List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());
  216. S2Loop s2Loop = new S2Loop(collect);
  217. S2Polygon polygon = new S2Polygon(s2Loop); //创建多边形
  218. S2Point s2Point = S2LatLng.fromDegrees(s.getLat(), s.getLng()).toPoint();
  219. boolean contains = polygon.contains(s2Point);
  220. return contains;
  221. }
  222. /**
  223. * 计算两个区域是否有交集
  224. *
  225. * @param vertices 形成多边形的点集合1
  226. * @param vertices2 形成多边形的点集合2
  227. * @return
  228. */
  229. public static boolean pointUniteArea(List<PointS2> vertices, List<PointS2> vertices2) {
  230. //因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下
  231. List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());
  232. //因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下
  233. List<S2Point> collect2 = vertices2.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());
  234. S2Loop s2Loop = new S2Loop(collect);
  235. S2Polygon polygon = new S2Polygon(s2Loop);
  236. S2Loop s2Loop2 = new S2Loop(collect2);
  237. S2Polygon polygon2 = new S2Polygon(s2Loop2);
  238. S2RegionCoverer coverer = new S2RegionCoverer();
  239. //设置cell
  240. coverer.setMinLevel(7);//设置最小级别
  241. coverer.setMaxLevel(15);//设置最大级别
  242. coverer.setMaxCells(500);//设置最大Cell
  243. S2CellUnion covering = coverer.getCovering(polygon2);
  244. for (S2CellId s2CellId : covering.cellIds()) {
  245. boolean b = polygon.mayIntersect(new S2Cell(s2CellId));
  246. if (b) {
  247. System.out.println("两个区域之间含有交集.....");
  248. }
  249. return b;
  250. }
  251. return false;
  252. }
  253. /**
  254. * 不同等级S2块包含的S2子块
  255. *
  256. * @param s 自己的点
  257. * @param level 自己的等级
  258. * @param desLevel 被计算的格子等级,注意:等级越大算的就越多
  259. * @return
  260. */
  261. public static List<S2CellId> childrenCellId(PointS2 s, Integer level, Integer desLevel) {
  262. S2LatLng s2LatLng = S2LatLng.fromDegrees(s.getLat(), s.getLng());
  263. S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(level);
  264. return childrenCellId(cellId, cellId.level(), desLevel);
  265. }
  266. //递归调用,每个格子一分为四
  267. private static List<S2CellId> childrenCellId(S2CellId s2CellId, Integer curLevel, Integer desLevel) {
  268. if (curLevel < desLevel) {
  269. //计算当前格子每个格子的差值
  270. long interval = (s2CellId.childEnd().id() - s2CellId.childBegin().id()) / 4;
  271. List<S2CellId> s2CellIds = Lists.newArrayList();
  272. for (int i = 0; i < 4; i++) {
  273. long id = s2CellId.childBegin().id() + interval * i;
  274. s2CellIds.addAll(childrenCellId(new S2CellId(id), curLevel + 1, desLevel));
  275. }
  276. return s2CellIds;
  277. } else {
  278. return Lists.newArrayList(s2CellId);
  279. }
  280. }
  281. /**
  282. * 任意形状内所有指定等级的S2块
  283. *
  284. * @param vertices 多边形的点
  285. * @param desevel 需要计算的内部的s2块的等级
  286. * @return
  287. */
  288. public static List<S2CellId> childrenCellId(List<PointS2> vertices, int desevel) {
  289. List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());
  290. S2Loop s2Loop = new S2Loop(collect);
  291. S2Polygon polygon = new S2Polygon(s2Loop);
  292. S2RegionCoverer coverer = new S2RegionCoverer();
  293. //设置cell
  294. coverer.setMinLevel(6);//设置最小级别 108km~151km
  295. coverer.setMaxLevel(11);//设置最大级别 3km~5km
  296. coverer.setMaxCells(500);//设置最大Cell
  297. S2CellUnion covering = coverer.getCovering(polygon);
  298. List<S2CellId> s2CellIds = covering.cellIds();
  299. int i=0;
  300. List<S2CellId> list=new ArrayList<>();
  301. for (S2CellId s2CellId : s2CellIds) {
  302. List<S2CellId> s2CellIds1 = childrenCellId(s2CellId, s2CellId.level(), desevel);
  303. list.addAll(s2CellIds1);
  304. }
  305. return list;
  306. }
  307. public static void main(String[] args) {
  308. double lat = 30.2;
  309. double lng = 116.3;
  310. int currentLevel = 13;
  311. S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);
  312. S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);
  313. System.err.println(cellId);
  314. String s = cellId.toToken();
  315. System.err.println(s);
  316. /* System.err.println("------------------------------");
  317. System.err.println(latLonToCellToken(lat,lng,1));
  318. System.err.println(latLonToCellToken(lat,lng,2));
  319. System.err.println(latLonToCellToken(lat,lng,3));
  320. System.err.println(latLonToCellToken(lat,lng,4));
  321. System.err.println(latLonToCellToken(lat,lng,5));
  322. System.err.println(latLonToCellToken(lat,lng,6));
  323. System.err.println(latLonToCellToken(lat,lng,7));
  324. System.err.println(latLonToCellToken(lat,lng,8));
  325. System.err.println(latLonToCellToken(lat,lng,9));
  326. System.err.println(latLonToCellToken(lat,lng,10));
  327. System.err.println(latLonToCellToken(lat,lng,11));
  328. System.err.println(latLonToCellToken(lat,lng,12));
  329. System.err.println(latLonToCellToken(lat,lng,13));
  330. System.err.println(latLonToCellToken(lat,lng,14));
  331. System.err.println(latLonToCellToken(lat,lng,15));
  332. System.err.println(latLonToCellToken(lat,lng,16));
  333. System.err.println(latLonToCellToken(lat,lng,17));
  334. System.err.println(latLonToCellToken(lat,lng,18));
  335. System.err.println(latLonToCellToken(lat,lng,19));
  336. System.err.println(latLonToCellToken(lat,lng,20));
  337. System.err.println(latLonToCellToken(lat,lng,21));
  338. System.err.println(latLonToCellToken(lat,lng,30));
  339. System.err.println("------------------------------");*/
  340. PointS2 pointS2 = cellIdToLatLon(cellId.id());
  341. System.err.println(pointS2);
  342. double distance = distance(new PointS2(55.8241, 137.8347), new PointS2(55.8271, 137.8347));
  343. System.err.println("距离为:" + distance + " m");
  344. boolean b = pointRectangleArea(new PointS2(41.808006669390046, 111.495546258779), new PointS2(47.55467105799515, 117.6168335999181),
  345. 30, new PointS2(45.47161041105891, 114.84087253252726));
  346. System.err.println("矩形-----------------" + b);
  347. boolean b2 = pointGardenArea(new PointS2(112.030500, 27.970271), 600.5, new PointS2(22.629164, 114.025514));
  348. System.err.println(b2);
  349. ArrayList<PointS2> pointS2s = new ArrayList<>();
  350. pointS2s.add(new PointS2(41.200195, 97.760681));
  351. pointS2s.add(new PointS2(41.827161, 103.119335));
  352. pointS2s.add(new PointS2(36.507585, 103.688463));
  353. pointS2s.add(new PointS2(35.895869, 98.743842));
  354. pointS2s.add(new PointS2(41.253179, 97.700277));
  355. boolean b1 = pointPolygonArea(pointS2s, new PointS2(39.470948, 100.302180));
  356. System.err.println("多边形-----------" + b1);
  357. System.err.println("多边形2-----------" + Ryamethod.ray2(39.470948f, 100.302180f, pointS2s));
  358. // boolean b3 = pointUniteArea(pointS2s, pointS2s);
  359. ArrayList<PointS2> pointS2s1 = Lists.newArrayList(new PointS2(1, 2), new PointS2(3, 4));
  360. boolean b3 = pointUniteArea(pointS2s, pointS2s1);
  361. System.err.println(b3);
  362. // List<S2CellId> s2CellIds1 = childrenCellId(new PointS2(39.470948, 100.302180), 10, 12);
  363. // for (S2CellId s2CellId : s2CellIds1) {
  364. // System.err.println("点下的s2的token------"+s2CellId.toToken());
  365. // }
  366. List<S2CellId> s2CellIds = childrenCellId(pointS2s, 10);
  367. // for (S2CellId s2CellId : s2CellIds) {
  368. // System.err.println("token------"+s2CellId.toToken());
  369. // }
  370. }
  371. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/138648
推荐阅读
相关标签
  

闽ICP备14008679号