| | |
| | | package com.flightfeather.uav.common.utils |
| | | |
| | | import kotlin.math.PI |
| | | import kotlin.math.asin |
| | | import kotlin.math.cos |
| | | import kotlin.math.sin |
| | | import kotlin.math.* |
| | | |
| | | object MapUtil { |
| | | |
| | | private const val Ea = 6378137 //赤道半径 |
| | | private const val Eb = 6356725 //极半径 |
| | | |
| | | // 坐标转换参数 |
| | | const val a = 6378245.0; //长半轴 |
| | | const val ee = 0.00669342162296594323; //扁率/*** GCJ02 转换为 WGS84* @param lng* @param lat* @returns {*[]}*/ |
| | | |
| | | /** |
| | | * 根据坐标点、距离和角度,获取另一个坐标 |
| | |
| | | |
| | | /** |
| | | * 获取两经纬度间的距离 |
| | | * @return 返回两点间距离,单位:米 |
| | | */ |
| | | fun getDistance(lng1: Double, lat1: Double, lng2: Double, lat2: Double): Double { |
| | | // lat1 = lat1 || 0; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 计算多边形的四至范围 |
| | | * @param polygon 多边形坐标点数组 |
| | | * @return 四至范围,顺序为最小经度,最大经度, 最小纬度,最大纬度 |
| | | */ |
| | | fun calFourBoundaries(polygon: List<Pair<Double, Double>>): List<Double> { |
| | | // 计算多边形顶点经度范围和纬度范围 |
| | | val xsSort = polygon.map { it.first }.sorted() |
| | | val ysSort = polygon.map { it.second }.sorted() |
| | | |
| | | val xMin = xsSort[0] |
| | | val yMin = ysSort[0] |
| | | val xMax = xsSort[xsSort.lastIndex] |
| | | val yMax = ysSort[ysSort.lastIndex] |
| | | |
| | | return listOf(xMin, xMax, yMin, yMax) |
| | | } |
| | | |
| | | /** |
| | | * 判断坐标点是否在多边形的四至范围内 |
| | | * @param point 坐标点 |
| | | * @param polygon 多边形坐标点数组 |
| | |
| | | val x = point.first |
| | | val y = point.second |
| | | // 计算多边形顶点经度范围和纬度范围 |
| | | val xsSort = polygon.map { it.first }.sorted() |
| | | val ysSort = polygon.map { it.second }.sorted() |
| | | val fb = calFourBoundaries(polygon) |
| | | // val xsSort = polygon.map { it.first }.sorted() |
| | | // val ysSort = polygon.map { it.second }.sorted() |
| | | // |
| | | // val xMin = xsSort[0] |
| | | // val yMin = ysSort[0] |
| | | // val xMax = xsSort[xsSort.lastIndex] |
| | | // val yMax = ysSort[ysSort.lastIndex] |
| | | |
| | | val xMin = xsSort[0] |
| | | val yMin = ysSort[0] |
| | | val xMax = xsSort[xsSort.lastIndex] |
| | | val yMax = ysSort[ysSort.lastIndex] |
| | | val xMin = fb[0] |
| | | val xMax = fb[1] |
| | | val yMin = fb[2] |
| | | val yMax = fb[3] |
| | | |
| | | return x >= xMin && x <= xMax && y >= yMin && y <= yMax |
| | | } |
| | |
| | | * @param point 坐标点 |
| | | * @param polygon 多边形坐标点数组 |
| | | */ |
| | | fun inPolygon(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>):Boolean { |
| | | fun inPolygon(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | val x = point.first |
| | | val y = point.second |
| | | var j = polygon.size - 1 |
| | |
| | | * 判断坐标点是否在多边形内部 |
| | | */ |
| | | fun isPointInPolygon(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | if (polygon.size < 4) throw IllegalArgumentException("not a polygon") |
| | | if (polygon.size < 3) throw IllegalArgumentException("not a polygon") |
| | | |
| | | // 不在四至范围内,则一定不在多边形内 |
| | | if (!inBBox(point, polygon)) return false |
| | |
| | | // 计算是否在多边形内部 |
| | | return inPolygon(point, polygon) |
| | | } |
| | | |
| | | /** |
| | | * 判断经纬度是否在国内 |
| | | * @return true: 经纬度不在国内,false:经纬度在国内 |
| | | */ |
| | | fun outOfChina(point: Pair<Double, Double>): Boolean { |
| | | val lng = point.first |
| | | val lat = point.second |
| | | return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55) |
| | | } |
| | | |
| | | private fun transformLat(point: Pair<Double, Double>): Double { |
| | | val lng = point.first |
| | | val lat = point.second |
| | | var ret = -100.0 + |
| | | 2.0 * lng + |
| | | 3.0 * lat + |
| | | 0.2 * lat * lat + |
| | | 0.1 * lng * lat + |
| | | 0.2 * sqrt(abs(lng)) |
| | | ret += ((20.0 * sin(6.0 * lng * PI) + 20.0 * sin(2.0 * lng * PI)) * 2.0) / 3.0 |
| | | ret += ((20.0 * sin(lat * PI) + 40.0 * sin((lat / 3.0) * PI)) * 2.0) / 3.0 |
| | | ret += ((160.0 * sin((lat / 12.0) * PI) + 320 * sin((lat * PI) / 30.0)) * 2.0) / 3.0 |
| | | return ret; |
| | | } |
| | | |
| | | private fun transformLng(point: Pair<Double, Double>): Double { |
| | | val lng = point.first |
| | | val lat = point.second |
| | | var ret = 300.0 + |
| | | lng + |
| | | 2.0 * lat + |
| | | 0.1 * lng * lng + |
| | | 0.1 * lng * lat + |
| | | 0.1 * sqrt(abs(lng)); |
| | | ret += ((20.0 * sin(6.0 * lng * PI) + 20.0 * sin(2.0 * lng * PI)) * 2.0) / 3.0; |
| | | ret += ((20.0 * sin(lng * PI) + 40.0 * sin((lng / 3.0) * PI)) * 2.0) / 3.0; |
| | | ret += ((150.0 * sin((lng / 12.0) * PI) + 300.0 * sin((lng / 30.0) * PI)) * 2.0) / 3.0 |
| | | return ret; |
| | | } |
| | | |
| | | /** |
| | | * 火星坐标系转WGS84坐标系 |
| | | */ |
| | | fun gcj02ToWgs84(point: Pair<Double, Double>): Pair<Double, Double> { |
| | | if (outOfChina(point)) { |
| | | return point; |
| | | } else { |
| | | val lng = point.first |
| | | val lat = point.second |
| | | var dlat = transformLat(lng - 105.0 to lat - 35.0); |
| | | var dlng = transformLng(lng - 105.0 to lat - 35.0); |
| | | val radlat = (lat / 180.0) * PI; |
| | | var magic = sin(radlat); |
| | | magic = 1 - ee * magic * magic; |
| | | val sqrtmagic = sqrt(magic); |
| | | dlat = (dlat * 180.0) / (((a * (1 - ee)) / (magic * sqrtmagic)) * PI); |
| | | dlng = (dlng * 180.0) / ((a / sqrtmagic) * cos(radlat) * PI); |
| | | val mglat = Math.round((lat * 2 - lat - dlat) * 1000000).toDouble() / 1000000; |
| | | val mglng = Math.round((lng * 2 - lng - dlng) * 1000000).toDouble() / 1000000; |
| | | return mglng to mglat |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * WGS84坐标系转火星坐标系 |
| | | */ |
| | | fun wgs84ToGcj02(point: Pair<Double, Double>): Pair<Double, Double> { |
| | | if (outOfChina(point)) { |
| | | return point |
| | | } else { |
| | | val lng = point.first |
| | | val lat = point.second |
| | | var dLat = transformLat(lng - 105.0 to lat - 35.0); |
| | | var dLon = transformLng(lng - 105.0 to lat - 35.0); |
| | | val radLat = (lat / 180.0) * PI; |
| | | var magic = sin(radLat); |
| | | magic = 1 - ee * magic * magic; |
| | | val sqrtMagic = sqrt(magic); |
| | | dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * PI); |
| | | dLon = (dLon * 180.0) / ((a / sqrtMagic) * cos(radLat) * PI); |
| | | val mgLat = lat + dLat; |
| | | val mgLon = lng + dLon; |
| | | return mgLon to mgLat |
| | | } |
| | | } |
| | | } |