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(单元格数)
0 85011012.19 85011012.19 85011012.19 km2 7842 km 7842 km 7842 km 7842 km 6
1 21252753.05 21252753.05 21252753.05 km2 3921 km 5004 km 3921 km 5004 km 24
2 4919708.23 6026521.16 5313188.26 km2 1825 km 2489 km 1825 km 2489 km 96
3 1055377.48 1646455.5 1328297.07 km2 840 km 1167 km 1130 km 1310 km 384
4 231564.06 413918.15 332074.27 km2 432 km 609 km 579 km 636 km 1536
5 53798.67 104297.91 83018.57 km2 210 km 298 km 287 km 315 km 6K
6 12948.81 26113.3 20754.64 km2 108 km 151 km 143 km 156 km 24K
7 3175.44 6529.09 5188.66 km2 54 km 76 km 72 km 78 km 98K
8 786.2 1632.45 1297.17 km2 27 km 38 km 36 km 39 km 393K
9 195.59 408.12 324.29 km2 14 km 19 km 18 km 20 km 1573K
10 48.78 102.03 81.07 km2 7 km 9 km 9 km 10 km 6M
11 12.18 25.51 20.27 km2 3 km 5 km 4 km 5 km 25M
12 3.04 6.38 5.07 km2 1699 m 2 km 2 km 2 km 100M
13 0.76 1.59 1.27 km2 850 m 1185 m 1123 m 1225 m 402M
14 0.19 0.4 0.32 km2 425 m 593 m 562 m 613 m 1610M
15 47520.3 99638.93 79172.67 m2 212 m 296 m 281 m 306 m 6B
16 11880.08 24909.73 19793.17 m2 106 m 148 m 140 m 153 m 25B
17 2970.02 6227.43 4948.29 m2 53 m 74 m 70 m 77 m 103B
18 742.5 1556.86 1237.07 m2 27 m 37 m 35 m 38 m 412B
19 185.63 389.21 309.27 m2 13 m 19 m 18 m 19 m 1649B
20 46.41 97.3 77.32 m2 7 m 9 m 9 m 10 m 7T
21 11.6 24.33 19.33 m2 3 m 5 m 4 m 5 m 26T
22 2.9 6.08 4.83 m2 166 cm 2 m 2 m 2 m 105T
23 0.73 1.52 1.21 m2 83 cm 116 cm 110 cm 120 cm 422T
24 0.18 0.38 0.3 m2 41 cm 58 cm 55 cm 60 cm 1689T
25 453.19 950.23 755.05 cm2 21 cm 29 cm 27 cm 30 cm 7.00E+15
26 113.3 237.56 188.76 cm2 10 cm 14 cm 14 cm 15 cm 2.70E+16
27 28.32 59.39 47.19 cm2 5 cm 7 cm 7 cm 7 cm 1.08E+17
28 7.08 14.85 11.8 cm2 2 cm 4 cm 3 cm 4 cm 4.32E+17
29 1.77 3.71 2.95 cm2 12 mm 18 mm 17 mm 18 mm 1.73E+18
30 0.44 0.93 0.74 cm2 6 mm 9 mm 8 mm 9 mm 7.00E+18
package com.zz.meridian.utils.googleS2;/*** @author tiger* GPS位置信息接下来说下坐标系。目前主要有三种地理坐标系,如下:* 1、WGS84坐标系:即地球坐标系(World Geodetic System),国际上通用的坐标系。* 设备包含的GPS芯片或者北斗芯片获取的经纬度一般都是为WGS84地理坐标系,目前谷歌地图采用的是WGS84坐标系(中国范围除外)。* 2、GCJ02坐标系:即火星坐标系,国测局坐标系。是由中国国家测绘局制定。由WGS84坐标系经加密后的坐标系。谷歌中国和搜搜中国采用的GCJ02地理坐标系。* 3、BD09坐标系:百度坐标系,GCJ02坐标系经加密后的坐标系。* 4、其他(搜狗坐标系,图吧坐标系等)。大概率也是再GCJ02坐标系基础上加密生成的*/
public class PointS2Transform {public static double x_PI = 3.14159265358979324 * 3000.0 / 180.0;public static double PI = 3.1415926535897932384626;public static double a = 6378245.0;public static double ee = 0.00669342162296594323;/*** 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换* 即 百度 转 谷歌、高德** @param bd_lon* @param bd_lat* @returns {*[]}*/public static PointS2 bd09togcj02(double bd_lon, double bd_lat) {double x = bd_lon - 0.0065;double y = bd_lat - 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);double gg_lng = z * Math.cos(theta);double gg_lat = z * Math.sin(theta);PointS2 point = new PointS2(gg_lat, gg_lng);return point;}/*** 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换* 即谷歌、高德 转 百度** @param lng* @param lat* @returns {*[]}*/public static PointS2 gcj02tobd09(double lng, double lat) {double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);double bd_lng = z * Math.cos(theta) + 0.0065;double bd_lat = z * Math.sin(theta) + 0.006;PointS2 point = new PointS2(bd_lat, bd_lng);return point;};/*** WGS84转GCj02** @param lng* @param lat* @returns {*[]}*/public static PointS2 wgs84togcj02(double lng, double lat) {double dlat = transformlat(lng - 105.0, lat - 35.0);double dlng = transformlng(lng - 105.0, lat - 35.0);double radlat = lat / 180.0 * PI;double magic = Math.sin(radlat);magic = 1 - ee * magic * magic;double sqrtmagic = Math.sqrt(magic);dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);double mglat = lat + dlat;double mglng = lng + dlng;PointS2 point = new PointS2(mglat, mglng);return point;}/*** 84 to ⽕星坐标系 (GCJ-02) 是否离开了中国版** @param lat* @param lon*/public static PointS2 gps84_To_Gcj02(double lat, double lon) {if (outOfChina(lat, lon)) {return null;}double dLat = transformLat(lon - 105.0, lat - 35.0);double dLon = transformLon(lon - 105.0, lat - 35.0);double radLat = lat / 180.0 * PI;double magic = Math.sin(radLat);magic = 1 - ee * magic * magic;double sqrtMagic = Math.sqrt(magic);dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);double mgLat = lat + dLat;double mgLon = lon + dLon;return new PointS2(mgLat, mgLon);}/*** ⽕星坐标系 GCJ02 转换为 WGS84** @param lng* @param lat* @returns {*[]}*/public static PointS2 gcj02towgs84(double lng, double lat) {double dlat = transformlat(lng - 105.0, lat - 35.0);double dlng = transformlng(lng - 105.0, lat - 35.0);double radlat = lat / 180.0 * PI;double magic = Math.sin(radlat);magic = 1 - ee * magic * magic;double sqrtmagic = Math.sqrt(magic);dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);double mglat = lat + dlat;double mglng = lng + dlng;PointS2 point = new PointS2(mglat, mglng);return point;}/*** ⽕星坐标系 GCJ02 转换为 WGS84 是否离开了中国版* @param lon * @param lat * @return*/public static PointS2 gcj_To_Gps84(double lat, double lon) {PointS2 gps = transform(lat, lon);double lontitude = lon * 2 - gps.getLng();double latitude = lat * 2 - gps.getLat();return new PointS2(latitude, lontitude);}/*** 将 GCJ-02 坐标转换成 BD-09 坐标* @param gg_lat* @param gg_lon*/public static PointS2 gcj02_To_Bd09(double gg_lat, double gg_lon) {double x = gg_lon, y = gg_lat;double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * PI);double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * PI);double bd_lon = z * Math.cos(theta) + 0.0065;double bd_lat = z * Math.sin(theta) + 0.006;return new PointS2(bd_lat, bd_lon);}/*** 将 BD-09 坐标转换成GCJ-02 坐标* bd_lat * @param bd_lon * @return*/public static PointS2 bd09_To_Gcj02(double bd_lat, double bd_lon) {double x = bd_lon - 0.0065;double y = bd_lat - 0.006;double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * PI);double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * PI);double gg_lon = z * Math.cos(theta);double gg_lat = z * Math.sin(theta);return new PointS2(gg_lat, gg_lon);}/*** (BD-09)-->84** @param bd_lat* @param bd_lon* @return*/public static PointS2 bd09_To_Gps84(double bd_lat, double bd_lon) {PointS2 gcj02 = bd09_To_Gcj02(bd_lat, bd_lon);PointS2 map84 = gcj_To_Gps84(gcj02.getLat(),gcj02.getLng());return map84;}/*** is or not outOfChina* 是否离开了中国* @param lat* @param lon* @return*/public static boolean outOfChina(double lat, double lon) {if (lon < 72.004 || lon > 137.8347)return true;if (lat < 0.8293 || lat > 55.8271)return true;return false;}private static double transformlat(double lng, double lat) {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));ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;return ret;}private static double transformlng(double lng, double lat) {double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;return ret;}public static PointS2 transform(double lat, double lon) {if (outOfChina(lat, lon)) {return new PointS2(lat, lon);}double dLat = transformLat(lon - 105.0, lat - 35.0);double dLon = transformLon(lon - 105.0, lat - 35.0);double radLat = lat / 180.0 * PI;double magic = Math.sin(radLat);magic = 1 - ee * magic * magic;double sqrtMagic = Math.sqrt(magic);dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);double mgLat = lat + dLat;double mgLon = lon + dLon;return new PointS2(mgLat, mgLon);}public static double transformLat(double x, double y) {double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y+ 0.2 * Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;return ret;}public static double transformLon(double x, double y) {double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1* Math.sqrt(Math.abs(x));ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0* PI)) * 2.0 / 3.0;return ret;}
}
package com.zz.meridian.utils.googleS2;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class PointS2 {double lat;double lng;
}
package com.zz.meridian.utils.googleS2;import com.google.common.collect.Lists;
import com.google.common.geometry.*;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;/*** @author tiger* 必须使用-S2使用的是WGS84坐标* 如果你获得的是WGS84坐标-百度或者高德的地理坐标,请将其转换为GPS-WGS84坐标* 由于google s2默认使用gps坐标系,在国内无法使用,需要转换为国内的gcj坐标或者bd09坐标* 主要包含3类方法:* getS2RegionByXXX* 获取给定经纬度坐标对应的S2Region,该region可用于获取cellId,或用于判断包含关系* getCellIdList* 获取给定region的cellId,并通过childrenCellId方法控制其严格遵守minLevel* contains* 对于指定S2Region,判断经纬度或CellToken是否在其范围内*/
/*
包<dependency><groupId>io.sgr</groupId><artifactId>s2-geometry-library-java</artifactId><version>1.0.0</version></dependency>*/
public class GoogleS2 {/*** 经纬度 转 S2CellId** @param lat          维度* @param lng          经度* @param currentLevel level选择级别*/public static S2CellId latLonToS2LatLng(double lat, double lng, int currentLevel) {S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);return cellId;}/*** 经纬度 转 CellId** @param lat          维度* @param lng          经度* @param currentLevel level选择级别*/public static Long latLonToCellId(double lat, double lng, int currentLevel) {S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);return cellId.id();}/*** 经纬度 转 cellToken** @param lat          维度* @param lng          经度* @param currentLevel level选择级别*/public static String latLonToCellToken(double lat, double lng, int currentLevel) {try {S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);return cellId.toToken();} catch (Exception e) {e.printStackTrace();return null;}}/*** CellId 转 经纬度** @param cellId 是 S2CellId.id();* @return*/public static PointS2 cellIdToLatLon(Long cellId) {S2LatLng s2LatLng = new S2CellId(cellId).toLatLng();double lat = s2LatLng.latDegrees();double lng = s2LatLng.lngDegrees();return new PointS2(lat, lng);}/*** cellToken 转 经纬度** @param cellToken* @return*/public static PointS2 cellTokenToLatLon(String cellToken) {S2LatLng latLng = new S2LatLng(S2CellId.fromToken(cellToken).toPoint());return new PointS2(latLng.latDegrees(), latLng.lngDegrees());}/*** 判断region是否包含指定经纬度坐标** @param region* @param lat* @param lon* @return*/public static boolean contains(S2Region region, double lat, double lon) {S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lon);try {boolean contains = region.contains(new S2Cell(s2LatLng));return contains;} catch (NullPointerException e) {e.printStackTrace();return false;}}/*** 判断当前cellId的level** @param cellId* @return*/public static int getLevel(long cellId) {int n = 0;while (cellId % 2 == 0) {cellId = cellId / 2;n++;}return 30 - n / 2;}/*** 获取任意形状内所有S2块* 可以用于区域内目标检索,根据cellid建立索引,查询区域内cellid in (list)的区域** @param vertices 形成多边形的点集合* @return*/private static List<Long> vertices(List<PointS2> vertices) {//因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());S2Loop s2Loop = new S2Loop(collect);S2Polygon cap = new S2Polygon(s2Loop); //创建多边形//S2Region cap 任意区域S2RegionCoverer coverer = new S2RegionCoverer();//最小格子和最大格子,总格子数量coverer.setMinLevel(7);//设置最小级别coverer.setMaxLevel(15);//设置最大级别coverer.setMaxCells(500);//设置最大CellList<S2CellId> list = coverer.getCovering(cap).cellIds();
//        for (S2CellId s : list) {
//            System.out.println(s.id());
//        }return list.stream().map(S2CellId::id).collect(Collectors.toList());}/*** S2计算距离** @param s1 点1的经度 纬度* @param s2 点2的经度 纬度* @return*/public static double distance(PointS2 s1, PointS2 s2) {S2LatLng startS2 = S2LatLng.fromDegrees(s1.getLat(), s1.getLng());S2LatLng endS2 = S2LatLng.fromDegrees(s2.getLat(), s2.getLng());double distance = startS2.getEarthDistance(endS2);return distance;}/*** 计算地球上某个点是否在矩形区域内* 矩形的左下角点和矩形的右上角点通过纬度来判断,高低不然算不出来* @param s1 生成矩形的经纬度s1* @param s2 生成矩形的经纬度s2* @param s3 判断s3点是否在上面s1和s2的矩形中* @return*/public static boolean pointRectangleArea(PointS2 s1, PointS2 s2, int desLevel, PointS2 s3) {S2LatLngRect rect = null;if (s1.getLat() > s2.getLat()) {//两个点可以经纬度-构建S2矩形rect = new S2LatLngRect(S2LatLng.fromDegrees(s2.getLat(), s2.getLng()),S2LatLng.fromDegrees(s1.getLat(), s1.getLng()));} else {//两个点可以经纬度-构建S2矩形rect = new S2LatLngRect(S2LatLng.fromDegrees(s1.getLat(), s1.getLng()),S2LatLng.fromDegrees(s2.getLat(), s2.getLng()));}//设置矩形的大小S2RegionCoverer coverer = new S2RegionCoverer();//设置cellcoverer.setMinLevel(7);coverer.setMaxLevel(15);coverer.setMaxCells(500);S2CellUnion covering = coverer.getCovering(rect);S2LatLng s2LatLng = S2LatLng.fromDegrees(s3.getLat(), s3.getLng());return covering.contains(s2LatLng.toPoint());}/*** 计算点s2是否在圆中心为s1半径为capHeight的圆形区域内** @param s1* @param capHeight* @param s2* @return*/public static boolean pointGardenArea(PointS2 s1, double capHeight, PointS2 s2) {S2LatLng s2LatLng = S2LatLng.fromDegrees(s1.getLat(), s1.getLng());S2Cap cap = S2Cap.fromAxisHeight(s2LatLng.toPoint(), capHeight);S2LatLng s2LatLng2 = S2LatLng.fromDegrees(s2.getLat(), s2.getLng());boolean contains = cap.contains(s2LatLng2.toPoint());return contains;}/*** 判断点是否在任意形状内** @param vertices 形成多边形的点集合* @param s        判断的点* @return*/public static boolean pointPolygonArea(List<PointS2> vertices, PointS2 s) {//因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());S2Loop s2Loop = new S2Loop(collect);S2Polygon polygon = new S2Polygon(s2Loop); //创建多边形S2Point s2Point = S2LatLng.fromDegrees(s.getLat(), s.getLng()).toPoint();boolean contains = polygon.contains(s2Point);return contains;}/*** 计算两个区域是否有交集** @param vertices  形成多边形的点集合1* @param vertices2 形成多边形的点集合2* @return*/public static boolean pointUniteArea(List<PointS2> vertices, List<PointS2> vertices2) {//因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());//因为x一般表示经度 y轴表示纬度所以这儿需要参数需要对应一下List<S2Point> collect2 = vertices2.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());S2Loop s2Loop = new S2Loop(collect);S2Polygon polygon = new S2Polygon(s2Loop);S2Loop s2Loop2 = new S2Loop(collect2);S2Polygon polygon2 = new S2Polygon(s2Loop2);S2RegionCoverer coverer = new S2RegionCoverer();//设置cellcoverer.setMinLevel(7);//设置最小级别coverer.setMaxLevel(15);//设置最大级别coverer.setMaxCells(500);//设置最大CellS2CellUnion covering = coverer.getCovering(polygon2);for (S2CellId s2CellId : covering.cellIds()) {boolean b = polygon.mayIntersect(new S2Cell(s2CellId));if (b) {System.out.println("两个区域之间含有交集.....");}return b;}return false;}/*** 不同等级S2块包含的S2子块** @param s        自己的点* @param level    自己的等级* @param desLevel 被计算的格子等级,注意:等级越大算的就越多* @return*/public static List<S2CellId> childrenCellId(PointS2 s, Integer level, Integer desLevel) {S2LatLng s2LatLng = S2LatLng.fromDegrees(s.getLat(), s.getLng());S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(level);return childrenCellId(cellId, cellId.level(), desLevel);}//递归调用,每个格子一分为四private static List<S2CellId> childrenCellId(S2CellId s2CellId, Integer curLevel, Integer desLevel) {if (curLevel < desLevel) {//计算当前格子每个格子的差值long interval = (s2CellId.childEnd().id() - s2CellId.childBegin().id()) / 4;List<S2CellId> s2CellIds = Lists.newArrayList();for (int i = 0; i < 4; i++) {long id = s2CellId.childBegin().id() + interval * i;s2CellIds.addAll(childrenCellId(new S2CellId(id), curLevel + 1, desLevel));}return s2CellIds;} else {return Lists.newArrayList(s2CellId);}}/*** 任意形状内所有指定等级的S2块** @param vertices 多边形的点* @param desevel  需要计算的内部的s2块的等级* @return*/public static List<S2CellId> childrenCellId(List<PointS2> vertices, int desevel) {List<S2Point> collect = vertices.stream().map(e -> S2LatLng.fromDegrees(e.getLng(), e.getLat()).toPoint()).collect(Collectors.toList());S2Loop s2Loop = new S2Loop(collect);S2Polygon polygon = new S2Polygon(s2Loop);S2RegionCoverer coverer = new S2RegionCoverer();//设置cellcoverer.setMinLevel(6);//设置最小级别  108km~151kmcoverer.setMaxLevel(11);//设置最大级别 3km~5kmcoverer.setMaxCells(500);//设置最大CellS2CellUnion covering = coverer.getCovering(polygon);List<S2CellId> s2CellIds = covering.cellIds();int i=0;List<S2CellId> list=new ArrayList<>();for (S2CellId s2CellId : s2CellIds) {List<S2CellId> s2CellIds1 = childrenCellId(s2CellId, s2CellId.level(), desevel);list.addAll(s2CellIds1);}return list;}public static void main(String[] args) {double lat = 30.2;double lng = 116.3;int currentLevel = 13;S2LatLng s2LatLng = S2LatLng.fromDegrees(lat, lng);S2CellId cellId = S2CellId.fromLatLng(s2LatLng).parent(currentLevel);System.err.println(cellId);String s = cellId.toToken();System.err.println(s);/*  System.err.println("------------------------------");System.err.println(latLonToCellToken(lat,lng,1));System.err.println(latLonToCellToken(lat,lng,2));System.err.println(latLonToCellToken(lat,lng,3));System.err.println(latLonToCellToken(lat,lng,4));System.err.println(latLonToCellToken(lat,lng,5));System.err.println(latLonToCellToken(lat,lng,6));System.err.println(latLonToCellToken(lat,lng,7));System.err.println(latLonToCellToken(lat,lng,8));System.err.println(latLonToCellToken(lat,lng,9));System.err.println(latLonToCellToken(lat,lng,10));System.err.println(latLonToCellToken(lat,lng,11));System.err.println(latLonToCellToken(lat,lng,12));System.err.println(latLonToCellToken(lat,lng,13));System.err.println(latLonToCellToken(lat,lng,14));System.err.println(latLonToCellToken(lat,lng,15));System.err.println(latLonToCellToken(lat,lng,16));System.err.println(latLonToCellToken(lat,lng,17));System.err.println(latLonToCellToken(lat,lng,18));System.err.println(latLonToCellToken(lat,lng,19));System.err.println(latLonToCellToken(lat,lng,20));System.err.println(latLonToCellToken(lat,lng,21));System.err.println(latLonToCellToken(lat,lng,30));System.err.println("------------------------------");*/PointS2 pointS2 = cellIdToLatLon(cellId.id());System.err.println(pointS2);double distance = distance(new PointS2(55.8241, 137.8347), new PointS2(55.8271, 137.8347));System.err.println("距离为:" + distance + " m");boolean b = pointRectangleArea(new PointS2(41.808006669390046, 111.495546258779), new PointS2(47.55467105799515, 117.6168335999181),30, new PointS2(45.47161041105891, 114.84087253252726));System.err.println("矩形-----------------" + b);boolean b2 = pointGardenArea(new PointS2(112.030500, 27.970271), 600.5, new PointS2(22.629164, 114.025514));System.err.println(b2);ArrayList<PointS2> pointS2s = new ArrayList<>();pointS2s.add(new PointS2(41.200195, 97.760681));pointS2s.add(new PointS2(41.827161, 103.119335));pointS2s.add(new PointS2(36.507585, 103.688463));pointS2s.add(new PointS2(35.895869, 98.743842));pointS2s.add(new PointS2(41.253179, 97.700277));boolean b1 = pointPolygonArea(pointS2s, new PointS2(39.470948, 100.302180));System.err.println("多边形-----------" + b1);System.err.println("多边形2-----------" + Ryamethod.ray2(39.470948f, 100.302180f, pointS2s));//        boolean b3 = pointUniteArea(pointS2s, pointS2s);ArrayList<PointS2> pointS2s1 = Lists.newArrayList(new PointS2(1, 2), new PointS2(3, 4));boolean b3 = pointUniteArea(pointS2s, pointS2s1);System.err.println(b3);//        List<S2CellId> s2CellIds1 = childrenCellId(new PointS2(39.470948, 100.302180), 10, 12);
//        for (S2CellId s2CellId : s2CellIds1) {
//            System.err.println("点下的s2的token------"+s2CellId.toToken());
//        }List<S2CellId> s2CellIds = childrenCellId(pointS2s, 10);
//        for (S2CellId s2CellId : s2CellIds) {
//            System.err.println("token------"+s2CellId.toToken());
//        }}}

Java实现Google的S2算法工具类相关推荐

  1. Google的S2算法原理以及使用Java版本--部分参考自《高效的多维空间点索引算法》

    文章目录 相关资料 1.S2算法是什么? 2.为什么要使用S2算法? 3.S2的原理是什么? 1)球面坐标变换 2)球面坐标转平面坐标(降维) remark: 3)球面矩形投影修正 4)点与坐标轴点相 ...

  2. 国密算法java语言的实现:利用bcprov和hutool库分别实现国密SM4算法工具类,对称密钥

    SM4算法成为行业标准: SM4分组密码算法是2012年3月21日实施的一项行业标准: 2021年6月25日,我国SM4分组密码算法作为国际标准ISO/IEC 18033-3:2010/AMD1:20 ...

  3. Java学习总结:58(Collections工具类)

    Collections工具类 Java提供了一个集合的工具类--Collections,这个工具类可以实现List.Set.Map集合的操作.Collections类的常用方法如下: No. 方法 类 ...

  4. java配置文件工具类,java项目加载配置文件的工具类

    java项目加载配置文件的工具类 package com.loadproperties; import java.io.IOException; import java.io.InputStream; ...

  5. Java 图片添加数字暗水印工具类

    Java 图片添加数字暗水印工具类. package cnki.thesis.common.utils;import org.opencv.core.*;import java.util.ArrayL ...

  6. Java时间戳与日期格式转换工具类

    Java时间戳与日期格式转换工具类 在做web开发时,有时候需要用到时间戳,在前台进行日期转换,从数据库中取出来是日期格式的,这里记录下使用的转换工具类(这些都是静态方法,通过类名.方法的形式即可调用 ...

  7. java获取客户端的IP地址工具类

    java获取客户端的IP地址工具类 import java.net.InetAddress; import java.net.UnknownHostException;import javax.ser ...

  8. Java判断不为空的工具类总结

    Java判断不为空的工具类总结 1.Java判断是否为空的工具类,可以直接使用.包含,String字符串,数组,集合等等. 1 package com.bie.util; 2 3 import jav ...

  9. (10)Java泛型-Map集合-集合框架工具类-可变参数-静态导入

    -- 部分1.5新特性Java泛型-Map集合-集合框架工具类 泛型 概述: JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制. 对于泛型可以这样理解: 没有使用泛型时,只要是对 ...

最新文章

  1. java spring scope_如何在Spring中自定义scope的方法示例
  2. c++读取utf8文件_【Python】File文件对象
  3. 【云快讯】之四十五《Google在云服务领域认输?不,我们的重点是大数据》
  4. ASP.NETMVC View页面 序列化 c# Model 为 Json字符串
  5. 【Selenium】导出成py脚本的基础使用
  6. Qt 使用正则表达式进行字符串替换
  7. 如何基于K8s构建下一代DevOps平台?
  8. 用Java描述数据结构之线性表的顺序存储(顺序表),ArrayList及其方法的介绍
  9. 直接请求接口_「软件测试教程」基于postman进行接口测试实战
  10. 显式Intent 和隐式 Intent 的区别
  11. Vmware Update Manager安装错误,错误代码:25085
  12. sublime text3插件TrailingSpaces无法使用的解决方法
  13. 一文带你弄懂 CDN 技术的原理
  14. AD快捷键还原为默认配置
  15. 引用 孙悟空的师傅菩提祖师的真实真份和镇元大仙辈份排名+四大灵猴
  16. 计算机弹奏两只老虎爱跳舞,原神风物之诗琴乐谱大全 原神风物之诗琴谱乐谱弹奏攻略...
  17. c语言多个自我介绍编码,代码自我介绍.doc
  18. 精选大数据面试真题10道(附答案详细解析)
  19. 无线降噪耳机品牌推荐,值得入手的四款降噪蓝牙耳机
  20. 使用新浪微博登录组件

热门文章

  1. 二进制加权电容器阵列的构建公共质心布局和布线
  2. no package identifier when getting value for resource number 0x00000005
  3. android系统升级实现,疯狂升级的Android系统
  4. 三月模拟题——炉石传说
  5. 如何利用语音评测技术设计英语口语选择题
  6. 2020-10-23 集合+序列化+递归+多线程+泛型+枚举+单例+反射小记
  7. mysql学习应用_MySQL学习从这里出发!
  8. wps大纲栏显示在右边_5分钟帮你搞定PPT!金山偷偷上线WPS智能PPT完全免费
  9. vmvare虚拟机无法读取ntfs的U盘解决方法,以及更换镜像下载源
  10. JavaScript中事件的绑定与解绑