Kotlin地图坐标系转换

我是研究僧i 提交于 2019-12-30 19:13:05

1.效果图:

2.运行结果:

 E/TAG: 最初始的高德选点坐标: 113.402847,23.164699
 E/TAG: g84坐标点: 113.39732255710973,23.167184411566584
 E/TAG: g02的坐标点: 113.40284721155093,23.16469943818697
 E/TAG: 最终的坐标点: 113.40284698937967,23.164707045643137

3.说明:

最近碰到一个硬件,经纬度是gps获取的 ,在Android设备上,用高德地图显示的时候,出现了坐标偏移,此demo正是为了解决此事而来

4.添加高德地图引用:

    //3d地图 和导航
    implementation 'com.amap.api:navi-3dmap:latest.integration'
    //定位
    implementation 'com.amap.api:location:latest.integration'
    //搜索
    implementation 'com.amap.api:search:latest.integration'

5.主界面:

package com.example.admin.zkotlin

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.TextView
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.LatLng
import com.kaisavx.AircraftController.util.*
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity() {
    //经过测试  本例子中, 其实高德坐标 就是 火星坐标gcj02 误差非常小
    internal var lat = 23.164699 //大洋图文
    internal var lon = 113.402847
    private var oldposition: LatLng? = null  //最初始的高德选点坐标

    private var g84position: LatLng? = null  //最初始的高德选点坐标 转换成g84

    private var g02position: LatLng? = null  // g84 转g02

    private var endposition: LatLng? = null  //   g02 转  高德

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        oldposition = LatLng(lat, lon)
        tv_old_gaode!!.text = oldposition.toString()
        Log.e("TAG", "最初始的高德选点坐标: " + oldposition!!.longitude + "," + oldposition!!.latitude)

        g84position = gcj02towgs84(LatLng(oldposition!!.latitude, oldposition!!.longitude))
        tv_gps!!.text = g84position.toString()
        Log.e("TAG", "g84坐标点: " + g84position!!.longitude + "," + g84position!!.latitude)

        g02position = wgs84togcj02(g84position!!)
        tv_j02!!.text = g02position.toString()
        Log.e("TAG", "g02的坐标点: " + g02position!!.longitude + "," + g02position!!.latitude)

        btn_coord!!.setOnClickListener {
            endposition = convert(g84position!!, CoordinateConverter.CoordType.GPS) //设置需要转换的坐标点和坐标类型
            Log.e("TAG", "最终的坐标点: " + endposition!!.longitude + "," + endposition!!.latitude)
            tv_gaode!!.text = endposition.toString()
        }
    }

    /**
     * 根据类型 转换 坐标
     */
    private fun convert(sourceLatLng: LatLng, coord: CoordinateConverter.CoordType): LatLng {
        val converter = CoordinateConverter(this)
        // CoordType.GPS 待转换坐标类型
        converter.from(coord)
        // sourceLatLng待转换坐标点
        converter.coord(sourceLatLng)
        // 执行转换操作
        return converter.convert()
    }


}

6.主界面UI:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="高德选点的坐标:" />

    <TextView
        android:id="@+id/tv_old_gaode"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0.0" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="GPS-WGS84坐标:" />



    <TextView
        android:id="@+id/tv_gps"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0.0" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="火星坐标:" />



    <TextView
        android:id="@+id/tv_j02"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0.0" />

    <Button
        android:id="@+id/btn_coord"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始转换" />


    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="高德SDK转换后的坐标:" />

    <TextView
        android:id="@+id/tv_gaode"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="0.0:" />
</LinearLayout>

7.转换算法 MapUtils.kt,注意:经过这个算法算出来的坐标,还是会存在误差的,但是对于我们的商业应用来说,差不多够用了

package com.kaisavx.AircraftController.util

import android.graphics.Bitmap
import android.os.Environment
import android.util.Log
import com.amap.api.maps.AMap
import com.amap.api.maps.model.LatLng
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.geocoder.GeocodeResult
import com.amap.api.services.geocoder.GeocodeSearch
import com.amap.api.services.geocoder.RegeocodeQuery
import com.amap.api.services.geocoder.RegeocodeResult
import java.io.File
import java.io.FileOutputStream

/**
 * Created by windless on 2017/10/12.
 */
fun getLocationsCenter(locations: List<LatLng>): LatLng {
    if (locations.size == 1) {
        return locations.first()
    }

    var x = 0.0
    var y = 0.0
    var z = 0.0

    locations.forEach {
        val latitude = it.latitude * Math.PI / 180
        val longitude = it.longitude * Math.PI / 180

        x += Math.cos(latitude) * Math.cos(longitude)
        y += Math.cos(latitude) * Math.sin(longitude)
        z += Math.sin(latitude)
    }

    x /= locations.size
    y /= locations.size
    z /= locations.size

    val centerLongitude = Math.atan2(y, x)
    val centerSquareRoot = Math.sqrt(x * x + y * y)
    val centerLatitude = Math.atan2(z, centerSquareRoot)
    return LatLng(centerLatitude * 180 / Math.PI, centerLongitude * 180 / Math.PI)
}

fun getMapScreenShootFile(fileName: String): File {
    val dir = Environment.getExternalStorageDirectory()
    val mapScreenShootDir = File(File(dir, "jellyfish"), "maps")
    return File(mapScreenShootDir, fileName)
}

fun saveMapScreenShoot(map: AMap, fileName: String) {
    val dir = Environment.getExternalStorageDirectory()
    val mapScreenShootDir = File(File(dir, "jellyfish"), "maps")
    if (!mapScreenShootDir.exists()) {
        mapScreenShootDir.mkdirs()
    }

    val filePath = File(mapScreenShootDir, fileName)

    map.getMapScreenShot(object : AMap.OnMapScreenShotListener {
        override fun onMapScreenShot(bitmap: Bitmap?) {
            if (bitmap == null) {
                return
            }
            if (filePath.exists()) {
                filePath.delete()
            }
            val fos = FileOutputStream(filePath)
            val ok = bitmap.compress(Bitmap.CompressFormat.PNG, 50, fos)
            if (ok) {
                try {
                    fos.flush()
                } catch (e: Exception) {
                    Log.d("MapUtils", "save map screen shoot failed", e)
                }
                try {
                    fos.close()
                } catch (ignored: Exception) {
                }
            }
        }

        override fun onMapScreenShot(bitmap: Bitmap?, status: Int) {
            Log.d("MapUtils", "$status")
        }
    })
}

val x_PI = 3.14159265358979324 * 3000.0 / 180.0
val PI = 3.1415926535897932384626
val a = 6378245.0
val ee = 0.00669342162296594323

fun wgs84togcj02(latlng: LatLng): LatLng {
    val lat = latlng.latitude
    val lng = latlng.longitude
    if (outOfChina(lng, lat)) {
        return latlng
    } else {
        var dlat = transformlat(lng - 105.0, lat - 35.0)
        var dlng = transformlng(lng - 105.0, lat - 35.0)
        val radlat = lat / 180.0 * PI
        var magic = Math.sin(radlat)
        magic = 1 - ee * magic * magic
        val sqrtmagic = Math.sqrt(magic)
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
        val mglat = lat + dlat
        val mglng = lng + dlng
        return LatLng(mglat, mglng)
    }
}

fun gcj02towgs84(latlng: LatLng): LatLng {
    val lat = latlng.latitude
    val lng = latlng.longitude
    if (outOfChina(lng, lat)) {
        return latlng
    } else {
        var dlat = transformlat(lng - 105.0, lat - 35.0)
        var dlng = transformlng(lng - 105.0, lat - 35.0)
        val radlat = lat / 180.0 * PI
        var magic = Math.sin(radlat)
        magic = 1 - ee * magic * magic
        val sqrtmagic = Math.sqrt(magic)
        dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI)
        dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI)
        val mglat = lat + dlat
        val mglng = lng + dlng
        return LatLng(
                lat * 2 - mglat,
                lng * 2 - mglng
        )
    }
}


private fun outOfChina(lng: Double, lat: Double): Boolean {
    return (lng < 72.004 || lng > 137.8347) && (lat < 0.8293 || lat > 55.8271)
}

private fun transformlat(lng: Double, lat: Double): Double {
    var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat
    + 0.2 * Math.sqrt(Math.abs(lng))
    ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
    ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0
    ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0
    return ret
}

private fun transformlng(lng: Double, lat: Double): Double {
    var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat
    + 0.1 * Math.sqrt(Math.abs(lng))
    ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0
    ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0
    ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0
    return ret
}

end

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!