feiyu02
2025-08-05 176d7d8283e66ccf63878c9ab823e900df94b748
src/main/kotlin/com/flightfeather/uav/common/net/AMapService.kt
@@ -1,19 +1,153 @@
package com.flightfeather.uav.common.net
import com.flightfeather.uav.common.exception.BizException
import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import org.apache.http.util.EntityUtils
import java.net.URLEncoder
import java.nio.charset.Charset
/**
 * 高德地图Web服务API
 * Date: 2024/07/14
 */
object AMapService {
    private const val TAG = "AMapService"
    private const val KEY = "b36a93bac8950d3d7c6c06f21133de51"
    private val httpMethod = HttpMethod("restapi.amap.com", 443, true)
    private val KEY = ""
    data class AMapAddress(
        val country: String,
        val province: String,
        val city: String,
        val citycode: String,
        val district: String,
        val adcode: String,
        val township: String,
        val towncode: String,
        val street: String,
    )
    data class AMapDirection(
        // 路线类型,driving: 驾车;
        val type: String,
        // 起点经纬度
        val origin: Pair<Double, Double>,
        // 终点经纬度
        val destination: Pair<Double, Double>,
        // 途径路线经纬度(不包括起点终点)
        val paths: List<Pair<Double, Double>>,
        // 方案距离,单位:米
        val distance: String
    )
    /**
     * 驾车路线规划
     */
    fun directionDriving(origin: Pair<Double, Double>, destination: Pair<Double, Double>):AMapDirection {
        val res = httpMethod.get(
            "/v5/direction/driving", listOf(
                "key" to KEY,
                "origin" to "${origin.first},${origin.second}",
                "destination" to "${destination.first},${destination.second}",
                "show_fields" to "polyline"
            )
        )
        val obj = handleRes(res)
        try {
            val count = obj["count"].asString.toIntOrNull()
            if (count != null && count > 0) {
                val path = obj["route"].asJsonObject["paths"].asJsonArray.get(0).asJsonObject
                val finalPaths = mutableListOf<Pair<Double,Double>>()
                path["steps"].asJsonArray.forEach {
                    finalPaths.addAll(
                        it.asJsonObject["polyline"].asString.split(";").map { str->
                            val strArr = str.split(",")
                            strArr[0].toDouble() to strArr[1].toDouble()
                        }
                    )
                }
                return AMapDirection("driving", origin, destination, finalPaths, path["distance"].asString)
            } else {
                throw BizException("高德API驾车路线规划失败,没有找到可行的路线")
            }
        } catch (e: Exception) {
            throw BizException("高德API驾车路线规划错误,${e.message}")
        }
    }
    /**
     * 地理逆编码
     * @param location 坐标点
     * @return 所在街道
     */
    fun reGeo(location:List<Pair<Double, Double>>) {
        httpMethod.get("v3/geocode/regeo", listOf(
    fun reGeo(location:Pair<Double, Double>):AMapAddress {
        val res = httpMethod.get("/v3/geocode/regeo", listOf(
            "key" to KEY,
            "location" to "${location.first},${location.second}"
        ))
        val obj = handleRes(res)
        try {
            val a = obj["regeocode"].asJsonObject["addressComponent"].asJsonObject
            return AMapAddress(
                a["country"].asString,
                a["province"].asString,
                "",
                a["citycode"].asString,
                a["district"].asString,
                a["adcode"].asString,
                a["township"].asString,
                a["towncode"].asString,
                a["streetNumber"].asJsonObject["street"].asString,
            )
        } catch (e: Exception) {
            throw BizException("高德API坐标转换错误,${e.message}", e.cause)
        }
    }
    /**
     * 坐标转换
     * @param locations 原始坐标
     * @param coordsys 原坐标系,可选值:gps;mapbar;baidu;autonavi(不进行转换)
     */
    fun coordinateConvert(locations: List<Pair<Double, Double>>, coordsys:String="gps"): List<Pair<Double, Double>> {
        val locationsStr = URLEncoder.encode(locations.joinToString("|") { "${it.first},${it.second}" }, "UTF-8")
        val res = httpMethod.get("/v3/assistant/coordinate/convert", listOf(
            "key" to KEY,
            "locations" to locationsStr,
            "coordsys" to coordsys
        ))
        val obj = handleRes(res)
        try {
            return obj["locations"].asString.split(";").map {
                val l = it.split(",")
                l[0].toDouble() to l[1].toDouble()
            }
        } catch (e: Exception) {
            throw BizException("高德API坐标转换错误,${e.message}")
        }
    }
    private fun handleRes(res: HttpMethod.MyResponse):JsonObject {
        if (res.success) {
            val str = EntityUtils.toString(res.m.entity)
            val json = JsonParser.parseString(str)
            return resCheck(json)
        } else {
            throw BizException("高德API网路链接错误,状态码:${res.m.statusLine.statusCode}")
        }
    }
    private fun resCheck(json: JsonElement): JsonObject {
        if (!json.isJsonObject) throw BizException("高德API失败,返回值不是一个object")
        val jo = json.asJsonObject
        if (jo["status"].asInt != 1) throw BizException("高德API失败,错误${jo["info"]}")
        return jo
    }
}