多种类型经纬度转换工具类
This commit is contained in:
parent
82b1413429
commit
01bd0e03ff
33
mylibrary/src/main/java/com/dahe/mylibrary/utils/Gps.java
Normal file
33
mylibrary/src/main/java/com/dahe/mylibrary/utils/Gps.java
Normal file
@ -0,0 +1,33 @@
|
||||
package com.dahe.mylibrary.utils;
|
||||
|
||||
/**
|
||||
* @ClassName Gps
|
||||
* @Author john
|
||||
* @Date 2024/12/13 17:25
|
||||
* @Description TODO
|
||||
*/
|
||||
public class Gps {
|
||||
private double wgLon;
|
||||
private double wgLat;
|
||||
|
||||
public Gps(double wgLat,double wgLon) {
|
||||
this.wgLat = wgLat;
|
||||
this.wgLon = wgLon;
|
||||
}
|
||||
|
||||
public double getWgLon() {
|
||||
return wgLon;
|
||||
}
|
||||
|
||||
public void setWgLon(double wgLon) {
|
||||
this.wgLon = wgLon;
|
||||
}
|
||||
|
||||
public double getWgLat() {
|
||||
return wgLat;
|
||||
}
|
||||
|
||||
public void setWgLat(double wgLat) {
|
||||
this.wgLat = wgLat;
|
||||
}
|
||||
}
|
@ -0,0 +1,539 @@
|
||||
package com.dahe.mylibrary.utils;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Address;
|
||||
import android.location.Criteria;
|
||||
import android.location.Geocoder;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author ondear
|
||||
* time : 16/11/13
|
||||
* desc : 定位相关工具类
|
||||
*/
|
||||
public class RxLocationUtils {
|
||||
|
||||
public static double pi = 3.1415926535897932384626;
|
||||
public static double a = 6378245.0;
|
||||
public static double ee = 0.00669342162296594323;
|
||||
private static OnLocationChangeListener mListener;
|
||||
private static MyLocationListener myLocationListener;
|
||||
private static LocationManager mLocationManager;
|
||||
|
||||
/**
|
||||
* 判断Gps是否可用
|
||||
*
|
||||
* @return {@code true}: 是<br>{@code false}: 否
|
||||
*/
|
||||
public static boolean isGpsEnabled(Context context) {
|
||||
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断定位是否可用
|
||||
*
|
||||
* @return {@code true}: 是<br>{@code false}: 否
|
||||
*/
|
||||
public static boolean isLocationEnabled(Context context) {
|
||||
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER) || lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开Gps设置界面
|
||||
*/
|
||||
public static void openGpsSettings(Context context) {
|
||||
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册
|
||||
* <p>使用完记得调用{@link #unregister()}</p>
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.INTERNET"/>}</p>
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>}</p>
|
||||
* <p>需添加权限 {@code <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>}</p>
|
||||
* <p>如果{@code minDistance}为0,则通过{@code minTime}来定时更新;</p>
|
||||
* <p>{@code minDistance}不为0,则以{@code minDistance}为准;</p>
|
||||
* <p>两者都为0,则随时刷新。</p>
|
||||
*
|
||||
* @param minTime 位置信息更新周期(单位:毫秒)
|
||||
* @param minDistance 位置变化最小距离:当位置距离变化超过此值时,将更新位置信息(单位:米)
|
||||
* @param listener 位置刷新的回调接口
|
||||
* @return {@code true}: 初始化成功<br>{@code false}: 初始化失败
|
||||
*/
|
||||
public static boolean register(Context context, long minTime, long minDistance, OnLocationChangeListener listener) {
|
||||
if (listener == null) return false;
|
||||
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
|
||||
ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
|
||||
return false;
|
||||
}
|
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
mListener = listener;
|
||||
if (!isLocationEnabled(context)) {
|
||||
ToastUtils.showToast(context, "无法定位,请打开定位服务");
|
||||
return false;
|
||||
}
|
||||
String provider = mLocationManager.getBestProvider(getCriteria(), true);
|
||||
|
||||
Location location = mLocationManager.getLastKnownLocation(provider);
|
||||
if (location != null) listener.getLastKnownLocation(location);
|
||||
if (myLocationListener == null) myLocationListener = new MyLocationListener();
|
||||
mLocationManager.requestLocationUpdates(provider, minTime, minDistance, myLocationListener);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
public static void unregister() {
|
||||
if (mLocationManager != null) {
|
||||
if (myLocationListener != null) {
|
||||
mLocationManager.removeUpdates(myLocationListener);
|
||||
myLocationListener = null;
|
||||
}
|
||||
mLocationManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置定位参数
|
||||
*
|
||||
* @return {@link Criteria}
|
||||
*/
|
||||
private static Criteria getCriteria() {
|
||||
Criteria criteria = new Criteria();
|
||||
//设置定位精确度 Criteria.ACCURACY_COARSE比较粗略,Criteria.ACCURACY_FINE则比较精细
|
||||
criteria.setAccuracy(Criteria.ACCURACY_FINE);
|
||||
//设置是否要求速度
|
||||
criteria.setSpeedRequired(false);
|
||||
// 设置是否允许运营商收费
|
||||
criteria.setCostAllowed(false);
|
||||
//设置是否需要方位信息
|
||||
criteria.setBearingRequired(false);
|
||||
//设置是否需要海拔信息
|
||||
criteria.setAltitudeRequired(false);
|
||||
// 设置对电源的需求
|
||||
criteria.setPowerRequirement(Criteria.POWER_LOW);
|
||||
return criteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取地理位置
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return {@link Address}
|
||||
*/
|
||||
public static Address getAddress(Context context, double latitude, double longitude) {
|
||||
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
|
||||
try {
|
||||
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
|
||||
if (addresses.size() > 0) return addresses.get(0);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取所在国家
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 所在国家
|
||||
*/
|
||||
public static String getCountryName(Context context, double latitude, double longitude) {
|
||||
Address address = getAddress(context, latitude, longitude);
|
||||
return address == null ? "unknown" : address.getCountryName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取所在地
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 所在地
|
||||
*/
|
||||
public static String getLocality(Context context, double latitude, double longitude) {
|
||||
Address address = getAddress(context, latitude, longitude);
|
||||
return address == null ? "unknown" : address.getLocality();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取所在街道
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 所在街道
|
||||
*/
|
||||
public static String getStreet(Context context, double latitude, double longitude) {
|
||||
Address address = getAddress(context, latitude, longitude);
|
||||
return address == null ? "unknown" : address.getAddressLine(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度获取详细地址
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param latitude 纬度
|
||||
* @param longitude 经度
|
||||
* @return 所在街道
|
||||
*/
|
||||
public static String getFeature(Context context, double latitude, double longitude) {
|
||||
Address address = getAddress(context, latitude, longitude);
|
||||
return address == null ? "未知地点" : address.getFeatureName();
|
||||
}
|
||||
|
||||
//------------------------------------------坐标转换工具start--------------------------------------
|
||||
|
||||
/**
|
||||
* GPS坐标 转换成 角度
|
||||
* 例如 113.202222 转换成 113°12′8″
|
||||
*
|
||||
* @param location
|
||||
* @return
|
||||
*/
|
||||
public static String gpsToDegree(double location) {
|
||||
double degree = Math.floor(location);
|
||||
double minute_temp = (location - degree) * 60;
|
||||
double minute = Math.floor(minute_temp);
|
||||
// double second = Math.floor((minute_temp - minute)*60);
|
||||
String second = new DecimalFormat("#.##").format((minute_temp - minute) * 60);
|
||||
return (int) degree + "°" + (int) minute + "′" + second + "″";
|
||||
}
|
||||
|
||||
/**
|
||||
* 国际 GPS84 坐标系
|
||||
* 转换成
|
||||
* [国测局坐标系] 火星坐标系 (GCJ-02)
|
||||
* <p>
|
||||
* World Geodetic System ==> Mars Geodetic System
|
||||
*
|
||||
* @param lon 经度
|
||||
* @param lat 纬度
|
||||
* @return GPS实体类
|
||||
*/
|
||||
public static Gps GPS84ToGCJ02(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 Gps(mgLat, mgLon);
|
||||
}
|
||||
|
||||
/**
|
||||
* [国测局坐标系] 火星坐标系 (GCJ-02)
|
||||
* 转换成
|
||||
* 国际 GPS84 坐标系
|
||||
*
|
||||
* @param lon 火星经度
|
||||
* @param lat 火星纬度
|
||||
*/
|
||||
public static Gps GCJ02ToGPS84(double lat, double lon) {
|
||||
Gps gps = transform(lat, lon);
|
||||
double lontitude = lon * 2 - gps.getWgLon();
|
||||
double latitude = lat * 2 - gps.getWgLat();
|
||||
return new Gps(latitude, lontitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* 火星坐标系 (GCJ-02)
|
||||
* 转换成
|
||||
* 百度坐标系 (BD-09)
|
||||
*
|
||||
* @param gg_lon 经度
|
||||
* @param gg_lat 纬度
|
||||
*/
|
||||
public static Gps GCJ02ToBD09(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 Gps(bd_lat, bd_lon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 国际 GPS84 坐标系
|
||||
* 转换成
|
||||
* 百度坐标系 (BD-09)
|
||||
*
|
||||
* @param lon 经度
|
||||
* @param lat 纬度
|
||||
*/
|
||||
public static Gps GPS84ToBD09(double lat, double lon) {
|
||||
Gps gps = GPS84ToGCJ02(lat,lon);
|
||||
if (gps == null) {
|
||||
return new Gps(lat,lon);
|
||||
}
|
||||
//GCJ-02 转 BD-09
|
||||
return GCJ02ToBD09(gps.getWgLat(), gps.getWgLon());
|
||||
}
|
||||
|
||||
/**
|
||||
* 百度坐标系 (BD-09)
|
||||
* 转换成
|
||||
* 火星坐标系 (GCJ-02)
|
||||
*
|
||||
* @param bd_lon 百度*经度
|
||||
* @param bd_lat 百度*纬度
|
||||
* @return GPS实体类
|
||||
*/
|
||||
public static Gps BD09ToGCJ02(double bd_lat, double bd_lon) {
|
||||
double x = bd_lon - 0.0065, 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 Gps(gg_lat, gg_lon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 百度坐标系 (BD-09)
|
||||
* 转换成
|
||||
* 国际 GPS84 坐标系
|
||||
*
|
||||
* @param bd_lon 百度*经度
|
||||
* @param bd_lat 百度*纬度
|
||||
* @return GPS实体类
|
||||
*/
|
||||
public static Gps BD09ToGPS84(double bd_lat, double bd_lon) {
|
||||
Gps gcj02 = BD09ToGCJ02(bd_lat, bd_lon);
|
||||
Gps map84 = GCJ02ToGPS84(gcj02.getWgLat(),
|
||||
gcj02.getWgLon());
|
||||
return map84;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 不在中国范围内
|
||||
*
|
||||
* @param lon 经度
|
||||
* @param lat 纬度
|
||||
* @return boolean值
|
||||
*/
|
||||
public static boolean outOfChina(double lat, double lon) {
|
||||
if (lon < 72.004 || lon > 137.8347)
|
||||
return true;
|
||||
return lat < 0.8293 || lat > 55.8271;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转化算法
|
||||
*
|
||||
* @param lon
|
||||
* @param lat
|
||||
* @return
|
||||
*/
|
||||
public static Gps transform(double lat, double lon) {
|
||||
if (outOfChina(lat, lon)) {
|
||||
return new Gps(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 Gps(mgLat, mgLon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 纬度转化算法
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 经度转化算法
|
||||
*
|
||||
* @param x
|
||||
* @param y
|
||||
* @return
|
||||
*/
|
||||
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 interface OnLocationChangeListener {
|
||||
|
||||
/**
|
||||
* 获取最后一次保留的坐标
|
||||
*
|
||||
* @param location 坐标
|
||||
*/
|
||||
void getLastKnownLocation(Location location);
|
||||
|
||||
/**
|
||||
* 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
|
||||
*
|
||||
* @param location 坐标
|
||||
*/
|
||||
void onLocationChanged(Location location);
|
||||
|
||||
/**
|
||||
* provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数
|
||||
*
|
||||
* @param provider 提供者
|
||||
* @param status 状态
|
||||
* @param extras provider可选包
|
||||
*/
|
||||
void onStatusChanged(String provider, int status, Bundle extras);//位置状态发生改变
|
||||
|
||||
void onProviderEnabled(String provider);
|
||||
|
||||
void onProviderDisabled(String provider);
|
||||
}
|
||||
|
||||
private static class MyLocationListener
|
||||
implements LocationListener {
|
||||
/**
|
||||
* 当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发
|
||||
*
|
||||
* @param location 坐标
|
||||
*/
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
if (mListener != null) {
|
||||
mListener.onLocationChanged(location);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* provider的在可用、暂时不可用和无服务三个状态直接切换时触发此函数
|
||||
*
|
||||
* @param provider 提供者
|
||||
* @param status 状态
|
||||
* @param extras provider可选包
|
||||
*/
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (mListener != null) {
|
||||
mListener.onStatusChanged(provider, status, extras);
|
||||
}
|
||||
switch (status) {
|
||||
case LocationProvider.AVAILABLE:
|
||||
Log.d("onStatusChanged", "当前GPS状态为可见状态");
|
||||
break;
|
||||
case LocationProvider.OUT_OF_SERVICE:
|
||||
Log.d("onStatusChanged", "当前GPS状态为服务区外状态");
|
||||
break;
|
||||
case LocationProvider.TEMPORARILY_UNAVAILABLE:
|
||||
Log.d("onStatusChanged", "当前GPS状态为暂停服务状态");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* provider被enable时触发此函数,比如GPS被打开
|
||||
*/
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
if (mListener != null) {
|
||||
mListener.onProviderEnabled(provider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* provider被disable时触发此函数,比如GPS被关闭
|
||||
*/
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
if (mListener != null) {
|
||||
mListener.onProviderDisabled(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
//===========================================坐标转换工具end====================================
|
||||
|
||||
|
||||
|
||||
private static final double EARTH_RADIUS = 6378137.0; //地球半径
|
||||
|
||||
|
||||
/**
|
||||
* 计算两个经纬度之间的距离
|
||||
*
|
||||
* @param longitude
|
||||
* @param latitude
|
||||
* @param longitude2
|
||||
* @param latitude2
|
||||
* @return 单位米
|
||||
*/
|
||||
public static double getDistance(double longitude, double latitude, double longitude2, double latitude2) {
|
||||
double lat1 = rad(latitude);
|
||||
double lat2 = rad(latitude2);
|
||||
double a = lat1 - lat2;
|
||||
double b = rad(longitude) - rad(longitude2);
|
||||
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
|
||||
s = s * EARTH_RADIUS;
|
||||
s = Math.round(s * 10000) / 10000; //四舍五入
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 弧度换为角度
|
||||
* @param d
|
||||
* @return
|
||||
*/
|
||||
private static double rad(double d) {
|
||||
return d * Math.PI / 180.0;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user