一个基于经纬度操作的地图的工具类分享:区域重叠、点是否在区域内、不同坐标系的经纬度转换、线段是否穿过区域、两点计算中心点坐标、根据圆心坐标和半径得到圆弧坐标

一、高德地图、奥维地图、百度地图之前的互转,WGS-84坐标系、GCJ-02坐标系、BD-09坐标系之间的互转。(转)
高德地图、奥维地图、百度地图他们之间的坐标系不一样,所以把相同的经纬度坐标放在不同的地图上展示的位置也不一样,详细说明见下引用。工具类代码如下所示。

1.WGS-84原始坐标系,一般用国际GPS纪录仪记录下来的经纬度,通过GPS定位拿到的原始经纬度,Google和高德地图定位的的经纬度(国外)都是基于WGS-84坐标系的;但是在国内是不允许直接用WGS84坐标系标注的,必须经过加密后才能使用;
2.GCJ-02坐标系,又名“火星坐标系”,是我国国测局独创的坐标体系,由WGS-84加密而成,在国内,必须至少使用GCJ-02坐标系,或者使用在GCJ-02加密后再进行加密的坐标系,如百度坐标系。高德和Google在国内都是使用GCJ-02坐标系,可以说,GCJ-02是国内最广泛使用的坐标系;
3.百度坐标系:bd-09,百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系,只适用于百度地图。(目前百度API提供了从其它坐标系转换为百度坐标系的API,但却没有从百度坐标系转为其他坐标系的API)
作者:青檬可乐
链接:https://www.jianshu.com/p/d3dd4149bb0b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/**
 * 坐标转换工具
 * 奥维地图:WGS-84坐标系
 * 高德地图、Google地图:GCJ-02坐标系
 * 百度坐标系:BD-09坐标系  百度坐标系是在GCJ-02坐标系的基础上再次加密偏移后形成的坐标系
 */
public class CoordinateTransitionUtils {
    public static double pi = 3.1415926535897932384626;  
    public static double x_pi = 3.14159265358979324 * 3000.0 / 180.0;  
    public static double a = 6378245.0;  
    public static double ee = 0.00669342162296594323;  
  
    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;  
    }  
    public static double[] transform(double lat, double lon) {  
        if (outOfChina(lat, lon)) {  
            return new double[]{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 double[]{mgLat,mgLon};  
    }  
    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;  
    }  
    /** 
     * 84 to 火星坐标系 (GCJ-02) World Geodetic System ==> Mars Geodetic System
     * 奥维 ----> 高德、Google
     * @param initAxis -->"经度,纬度"这样形式的坐标
     * @return 火星坐标系坐标
     */  
    public static String gps84_To_Gcj02(String initAxis) {
        String[] split = initAxis.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        if (outOfChina(lat, lon)) {
            String resultAxis = lon+","+lat;
            return resultAxis;
        }  
        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;
        String resultAxis = mgLon+","+mgLat;
        return resultAxis;
    }  
  
    /** 
     *  火星坐标系 (GCJ-02) to 84 坐标系
     *  Google、高德 --> 奥维
     *  @param initAxis -->"经度,纬度"这样形式的坐标
     * */  
    public static String gcj02_To_Gps84(String initAxis) {
        String[] split = initAxis.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        double[] gps = transform(lat, lon);  
        double lontitude = lon * 2 - gps[1];  
        double latitude = lat * 2 - gps[0];
        String resultAxis = lontitude+","+latitude;
        return resultAxis;
    }  
    /** 
     * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
     * Google、高德 --> 百度坐标
     * @param initAxis -->"经度,纬度"这样形式的坐标
     */  
    public static String gcj02_To_Bd09(String initAxis) {
        String[] split = initAxis.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        double x = lon, y = lat;  
        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 tempLon = z * Math.cos(theta) + 0.0065;  
        double tempLat = z * Math.sin(theta) + 0.006;
        String resultAxis = tempLon+","+tempLat;
        return resultAxis;
    }  
  
    /** 
     * 火星坐标系 (GCJ-02)<----百度坐标系 (BD-09)
     * BD-09 坐标转换成GCJ-02 坐标
     * @param initAxis -->"经度,纬度"这样形式的坐标
     */  
    public static String bd09_To_Gcj02(String initAxis) {
        String[] split = initAxis.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        double x = lon - 0.0065, y = 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 tempLon = z * Math.cos(theta);  
        double tempLat = z * Math.sin(theta);
        String resultAxis = tempLon+","+tempLat;
        return resultAxis;
    }  
  
    /**
     * 将gps84转为bd09
     * @param initAxis -->"经度,纬度"这样形式的坐标
     * @return  /
     */  
    public static String gps84_To_bd09(String initAxis){
        String gcj02 = gps84_To_Gcj02(initAxis);
        String bd09 = gcj02_To_Bd09(gcj02);
        return bd09;  
    }
    /**
     * 将bd09转为gps84
     * @param initAxis -->"经度,纬度"这样形式的坐标
     * @return /
     */
    public static String bd09_To_gps84(String initAxis){
        String gcj02 = bd09_To_Gcj02(initAxis);
        String gps84 = gcj02_To_Gps84(gcj02);
        //保留小数点后六位
        String[] split = gps84.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        lon = retain6(lon);
        lat = retain6(lat);
        return lon+","+lat;
    }  
  
    /**
     * 保留小数点后六位
     * @param num 位数
     * @return /
     */  
    private static double retain6(double num){  
        String result = String .format("%.6f", num);  
        return Double.valueOf(result);  
    }  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
二、根据经纬度坐标判断两个区域是否重叠的工具类
这个工具类里面包含了根据经纬度坐标判断两个区域是否重叠、根据经纬度判断坐标点是否在区域内、判断根据两点的经纬度坐标连成的线段是否穿过某个区域、根据两个经纬度坐标点计算其连线的中心点坐标等功能,不多BB,附上代码。

/**
 * Author: oldou
 * Date: 2020/12/23
 * Description:判断两个区域是否重叠、根据两个坐标的经纬度连线判断该线段是否穿过某个区域
 */
public class AreaOverlapCheckUtils {
    /**
     * 判断线是否穿过某个区域
     * @param lineAxisList 两点确定一条直线的坐标集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @param AreaAxisList 区域的坐标集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @return /
     */
    public static boolean isLineAcrossArea(List<String> lineAxisList,List<String> AreaAxisList){
        List<Location> locationList1 = new ArrayList<>();
        List<Location> locationList2 = new ArrayList<>();
        /* 线的坐标转换处理*/
        for (String s : lineAxisList) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
            locationList1.add(location);
        }
        /* 区域的坐标转换处理*/
        for (String s : AreaAxisList) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
            locationList2.add(location);
        }
        //获取线的坐标线段
        List<Line> lineList = getLines(locationList1);
        //获取区域的线段
        List<Line> lineList2 = getLines(locationList2);
        //判断是否相交
        boolean isIntersect = isIntersect(lineList, lineList2);
        if (isIntersect) return true;
        //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
        boolean isPolygonInPolygon = isPolygonInPolygon(locationList1, locationList2);
        if (isPolygonInPolygon) return true;
        return false;
    }

    /**
     * 判断根据给定的区域经纬度判断两个区域是否有重叠地方  A
     * @param AreaList1 区域一坐标的字符串集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @param AreaList2 区域二坐标的字符串集合 {"经度1,纬度1","经度2,纬度2","经度3,纬度3".....}
     * @return 是否相交的标识
     */
    public static boolean isCoinCide(List<String> AreaList1, List<String> AreaList2) {
        List<Location> locationList1 = new ArrayList<>();
        List<Location> locationList2 = new ArrayList<>();
        /* 区域一转换*/
        for (String s : AreaList1) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
            locationList1.add(location);
        }
        /* 区域二转换*/
        for (String s : AreaList2) {
            String[] split = s.split(",");
            Location location = new Location(Double.parseDouble(split[0]),Double.parseDouble(split[1]));
            locationList2.add(location);
        }
        //获取四边形的线段
        List<Line> lineList = getLines(locationList1);
        //获取三角形的线段
        List<Line> lineList2 = getLines(locationList2);
        //判断是否相交
        boolean isIntersect = isIntersect(lineList, lineList2);
        if (isIntersect) return true;
        //如果不相交判断是否包含-由于没有相交线段只要存在点在多边形内就说明包含
        boolean isPolygonInPolygon = isPolygonInPolygon(locationList1, locationList2);
        if (isPolygonInPolygon) return true;
        return false;
    }

    /**
     * 判断线段是否相交,A的附属方法 B
     * @param locationList /
     * @param locationList2 /
     * @return /
     */
    private static boolean isPolygonInPolygon(List<Location> locationList, List<Location> locationList2) {
        //判断第一个多边形是否在第二个多边形内
        for (Location location : locationList) {
            boolean isPointInPolygon = isPointInPolygon(location, locationList2);
            if (isPointInPolygon) return true;
        }
        //判断第二个多边形是否在第一个多边形内
        for (Location location : locationList2) {
            boolean isPointInPolygon = isPointInPolygon(location, locationList);
            if (isPointInPolygon) return true;
        }
        return false;
    }

    /**
     * 判断点是否在区域内,B的附属方法
     * @param location
     * @param locationList2
     * @return
     */
    private static boolean isPointInPolygon(Location location, List<Location> locationList2) {
        //点是否在多边形内
        GeneralPath path = new GeneralPath();
        //设定多边形起始点
        path.moveTo(locationList2.get(0).getLongitude(), locationList2.get(0).getLatitude());
        for (Location l : locationList2) {
            path.lineTo(l.getLongitude(), l.getLatitude());
        }
        //图像完成,封闭
        path.moveTo(locationList2.get(0).getLongitude(), locationList2.get(0).getLatitude());
        //多边形结束
        path.closePath();
        return path.contains(location.getLongitude(), location.getLatitude());
    }

    /**
     * 判断线段是否相交 A的附属方法
     * @param lineList /
     * @param lineList2 /
     * @return /
     */
    private static boolean isIntersect(List<Line> lineList, List<Line> lineList2) {
        for (Line line : lineList) {
            for (Line line1 : lineList2) {
                //两条线段是否相交
                boolean b = Line2D.linesIntersect(line.location1.longitude, line.location1.latitude, line.location2.longitude, line.location2.latitude,
                        line1.location1.longitude, line1.location1.latitude, line1.location2.longitude, line1.location2.latitude);
                if (b) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 根据坐标经纬度获取线的方法
     * @param locationList /
     * @return /
     */
    private static List<Line> getLines(List<Location> locationList) {
        List<Line> lineList = new ArrayList();
        for (int i = 0; i < locationList.size(); i++) {
            if (i < locationList.size() - 1) {
                Location l = locationList.get(i);
                Location l2 = locationList.get(i + 1);
                Line line = new Line(l, l2);
                lineList.add(line);
            } else {
                Location l = locationList.get(i);
                Location l2 = locationList.get(0);
                Line line = new Line(l, l2);
                lineList.add(line);
            }
        }
        return lineList;
    }

    /**
     * 辅助静态类-线
     */
    public static class Line {
        private Location location1;//起点
        private Location location2;//终点

        public Line(Location location1, Location location2) {
            this.location1 = location1;
            this.location2 = location2;
        }

        public Location getLocation1() {
            return location1;
        }

        public void setLocation1(Location location1) {
            this.location1 = location1;
        }

        public Location getLocation2() {
            return location2;
        }

        public void setLocation2(Location location2) {
            this.location2 = location2;
        }

        @Override
        public String toString() {
            return "Line{" +
                    "location1=" + location1 +
                    ", location2=" + location2 +
                    '}';
        }
    }

    /**
     * 辅助静态类-坐标
     */
    public static class Location {

        private double longitude;//经度
        private double latitude;//纬度

        public Location(double longitude, double latitude) {
            this.longitude = longitude;
            this.latitude = latitude;
        }

        public double getLongitude() {
            return longitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public double getLatitude() {
            return latitude;
        }

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        @Override
        public String toString() {
            return "Location{" +
                    "longitude=" + longitude +
                    ", latitude=" + latitude +
                    '}';
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
根据两个坐标的经纬度,计算两点之间的中心点经纬度
/**
     * 根据输入的地点坐标计算中心点
     * @param startAxis 起点坐标 "经度,纬度"
     * @param endAxis 终点坐标 "经度,纬度"
     * @return 返回中心点坐标 "经度,纬度"
     */
    public static String getCenterPoint(String startAxis,String endAxis) {
        String[] arr = {startAxis,endAxis};
        int total = arr.length;
        double X = 0, Y = 0, Z = 0;
        for (int i = 0; i < arr.length; i++) {
            double lat, lon, x, y, z;
            lon = Double.parseDouble(arr[i].split(",")[0]) * Math.PI / 180;
            lat = Double.parseDouble(arr[i].split(",")[1]) * Math.PI / 180;
            x = Math.cos(lat) * Math.cos(lon);
            y = Math.cos(lat) * Math.sin(lon);
            z = Math.sin(lat);
            X += x;
            Y += y;
            Z += z;
        }
        X = X / total;
        Y = Y / total;
        Z = Z / total;
        double Lon = Math.atan2(Y, X);
        double Hyp = Math.sqrt(X * X + Y * Y);
        double Lat = Math.atan2(Z, Hyp);
        String centreAxis = (Lon * 180 / Math.PI) + "," + (Lat * 180 / Math.PI);
        return centreAxis;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
根据圆心坐标经纬度和半径,得到圆上的坐标
/**
     * 给定一个圆心的经纬度和半径,求圆弧上的坐标
     * @param centerPoint 经纬度坐标
     * @param radius 半径
     */
    public static List<String> getCircleAxis(Double[] centerPoint, int radius) {
        Double X; //经度
        Double Y; //纬度
        double r = 6371000.79;
        List<String> optionsAxis = new ArrayList<>();
        int numpoints = 360; // 角度
        double phase = 2 * Math.PI / numpoints;

        //画图
        for (int i = 0; i < numpoints; i++) {
            /**
             * 计算坐标点
             */
            double dx = (radius * Math.cos(i * phase));
            double dy = (radius * Math.sin(i * phase)); //乘以1.6 椭圆比例

            /**
             * 转换成经纬度
             */
            double dlng = dx / (r * Math.cos(centerPoint[1] * Math.PI / 180) * Math.PI / 180); //纬度的差值
            double dlat = dy / (r * Math.PI / 180);  // 经度的差值

            X = centerPoint[1] + dlat;
            Y = centerPoint[0] + dlng;
            String optAxis = Y+","+X;
            optionsAxis.add(optAxis);
        }
        return optionsAxis;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
注意
以上代码中的经纬度坐标,基本上都是 “经度,纬度” 这样的格式,请自行改动。对你有帮助的话记得点赞支持哦
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值