概述
最近在公司做的项目需要用到地图经纬度的一些操作,只能手动的去写一些算法,期间参考了网上很多朋友的博客,现在分享出来,希望对搞这块的朋友有所帮助。
一、高德地图、奥维地图、百度地图之前的互转,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);
}
}
二、根据经纬度坐标判断两个区域是否重叠的工具类
这个工具类里面包含了根据经纬度坐标判断两个区域是否重叠、根据经纬度判断坐标点是否在区域内、判断根据两点的经纬度坐标连成的线段是否穿过某个区域、根据两个经纬度坐标点计算其连线的中心点坐标等功能,不多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 +
'}';
}
}
}
根据两个坐标的经纬度,计算两点之间的中心点经纬度
/**
* 根据输入的地点坐标计算中心点
* @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;
}
根据圆心坐标经纬度和半径,得到圆上的坐标
/**
* 给定一个圆心的经纬度和半径,求圆弧上的坐标
* @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;
}
注意
以上代码中的经纬度坐标,基本上都是 “经度,纬度” 这样的格式,请自行改动。对你有帮助的话记得点赞支持哦。
最后
以上就是活泼康乃馨为你收集整理的一个基于经纬度操作的地图的工具类分享:区域重叠、点是否在区域内、不同坐标系的经纬度转换、线段是否穿过区域、两点计算中心点坐标、根据圆心坐标和半径得到圆弧坐标一、高德地图、奥维地图、百度地图之前的互转,WGS-84坐标系、GCJ-02坐标系、BD-09坐标系之间的互转。(转)二、根据经纬度坐标判断两个区域是否重叠的工具类根据两个坐标的经纬度,计算两点之间的中心点经纬度根据圆心坐标经纬度和半径,得到圆上的坐标注意的全部内容,希望文章能够帮你解决一个基于经纬度操作的地图的工具类分享:区域重叠、点是否在区域内、不同坐标系的经纬度转换、线段是否穿过区域、两点计算中心点坐标、根据圆心坐标和半径得到圆弧坐标一、高德地图、奥维地图、百度地图之前的互转,WGS-84坐标系、GCJ-02坐标系、BD-09坐标系之间的互转。(转)二、根据经纬度坐标判断两个区域是否重叠的工具类根据两个坐标的经纬度,计算两点之间的中心点经纬度根据圆心坐标经纬度和半径,得到圆上的坐标注意所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复