| | |
| | | package com.flightfeather.uav.common.utils |
| | | |
| | | import kotlin.math.PI |
| | | import kotlin.math.asin |
| | | import kotlin.math.cos |
| | | import kotlin.math.sin |
| | | |
| | |
| | | val lat = (dy / ec + pos.second * PI / 180.0) * 180.0 / PI |
| | | return Pair(lng, lat) |
| | | } |
| | | |
| | | /** |
| | | * 获取两个经纬度之间的角度(0度-360度) |
| | | */ |
| | | fun getAngle(lngA: Double, latA: Double, lngB: Double, latB: Double): Double { |
| | | val a = ((90 - latB) * Math.PI) / 180; |
| | | val b = ((90 - latA) * Math.PI) / 180; |
| | | val AOC_BOC = ((lngB - lngA) * Math.PI) / 180; |
| | | val cosc = cos(a) * Math.cos(b) + Math.sin(a) * Math.sin(b) * Math.cos(AOC_BOC); |
| | | val sinc = Math.sqrt(1 - cosc * cosc); |
| | | val sinA = (Math.sin(a) * Math.sin(AOC_BOC)) / sinc; |
| | | val A = (Math.asin(sinA) * 180) / Math.PI; |
| | | var res = 0.0; |
| | | if (lngB > lngA && latB > latA) res = A; |
| | | else if (lngB > lngA && latB < latA) res = 180 - A; |
| | | else if (lngB < lngA && latB < latA) res = 180 - A; |
| | | else if (lngB < lngA && latB > latA) res = 360 + A; |
| | | else if (lngB > lngA && latB == latA) res = 90.0; |
| | | else if (lngB < lngA && latB == latA) res = 270.0; |
| | | else if (lngB == lngA && latB > latA) res = 0.0; |
| | | else if (lngB == lngA && latB < latA) res = 180.0; |
| | | return res; |
| | | } |
| | | |
| | | /** |
| | | * 获取两经纬度间的距离 |
| | | * @return 返回两点间距离,单位:米 |
| | | */ |
| | | fun getDistance(lng1: Double, lat1: Double, lng2: Double, lat2: Double): Double { |
| | | // lat1 = lat1 || 0; |
| | | // lng1 = lng1 || 0; |
| | | // lat2 = lat2 || 0; |
| | | // lng2 = lng2 || 0; |
| | | |
| | | val rad1 = (lat1 * Math.PI) / 180.0; |
| | | val rad2 = (lat2 * Math.PI) / 180.0; |
| | | val a = rad1 - rad2; |
| | | val b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0; |
| | | val distance = |
| | | Ea * 2 * asin( |
| | | Math.sqrt( |
| | | Math.pow( |
| | | Math.sin(a / 2), |
| | | 2.0 |
| | | ) + Math.cos(rad1) * Math.cos(rad2) * Math.pow(Math.sin(b / 2), 2.0) |
| | | ) |
| | | ); |
| | | |
| | | return distance; |
| | | } |
| | | |
| | | /** |
| | | * 角度增减,确保角度处于0 - 360度之间 |
| | | * @param angle 原角度 |
| | | * @param offset 偏移量 |
| | | */ |
| | | fun plusAngle(angle: Double, offset: Double): Double { |
| | | val result = angle + offset; |
| | | return if (result > 360) { |
| | | result - 360; |
| | | } else if (result < 0) { |
| | | result + 360; |
| | | } else { |
| | | result; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断坐标点是否在多边形的四至范围内 |
| | | * @param point 坐标点 |
| | | * @param polygon 多边形坐标点数组 |
| | | */ |
| | | fun inBBox(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | |
| | | val x = point.first |
| | | val y = point.second |
| | | // 计算多边形顶点经度范围和纬度范围 |
| | | 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 x >= xMin && x <= xMax && y >= yMin && y <= yMax |
| | | } |
| | | |
| | | /** |
| | | * 判断坐标点是否在多边形的边上 |
| | | * @param point 坐标点 |
| | | * @param polygon 多边形坐标点数组 |
| | | */ |
| | | fun onBorder(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | var res = false |
| | | // 循环判断每一条边 |
| | | for (i in polygon.indices) { |
| | | val p1 = polygon[i] |
| | | val p2 = if (i + 1 == polygon.size) { |
| | | polygon[0] |
| | | } else { |
| | | polygon[i + 1] |
| | | } |
| | | // 计算边的两个顶点纬度差和经度差的比值 |
| | | val k1 = (p2.second - p1.second) / (p2.first - p1.first) |
| | | // 计算坐标点和其中一个顶点的纬度差和经度差的比值 |
| | | val k2 = (p2.second - point.second) / (p2.first - point.first) |
| | | // 如果比值相同,说明三个点在同一直线上,即坐标点在边上 |
| | | if (k1 == k2) { |
| | | res = true |
| | | break |
| | | } |
| | | } |
| | | return res |
| | | } |
| | | |
| | | /** |
| | | * 判断坐标点是否在多边形内部(射线法) |
| | | * @param point 坐标点 |
| | | * @param polygon 多边形坐标点数组 |
| | | */ |
| | | 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 |
| | | var odd = false |
| | | for (i in polygon.indices) { |
| | | if ( |
| | | ((polygon[i].second > y) != (polygon[j].second > y)) |
| | | && (x < ((polygon[j].first - polygon[i].first) * (y - polygon[i].second) |
| | | / (polygon[j].second - polygon[i].second) + polygon[i].first)) |
| | | ) { |
| | | odd = !odd; |
| | | } |
| | | j = i; |
| | | } |
| | | return odd |
| | | } |
| | | |
| | | /** |
| | | * 判断坐标点是否在多边形内部 |
| | | */ |
| | | fun isPointInPolygon(point: Pair<Double, Double>, polygon: List<Pair<Double, Double>>): Boolean { |
| | | if (polygon.size < 3) throw IllegalArgumentException("not a polygon") |
| | | |
| | | // 不在四至范围内,则一定不在多边形内 |
| | | if (!inBBox(point, polygon)) return false |
| | | // 在多边形边上,也认为在多边形内 |
| | | if (onBorder(point, polygon)) return true |
| | | // 计算是否在多边形内部 |
| | | return inPolygon(point, polygon) |
| | | } |
| | | } |