package cn.flightfeather.thirdappmodule.module.base
|
|
import android.graphics.Color
|
import android.os.Build
|
import android.os.Bundle
|
import android.util.SparseArray
|
import android.view.WindowManager
|
import cn.flightfeather.thirdappmodule.R
|
import cn.flightfeather.thirdappmodule.util.CommonUtils
|
import cn.flightfeather.thirdappmodule.util.Domain
|
import cn.flightfeather.thirdappmodule.util.crashreport.MyCrashHandler
|
import com.amap.api.maps.*
|
import com.amap.api.maps.model.*
|
import com.amap.api.services.district.DistrictItem
|
import com.amap.api.services.district.DistrictSearch
|
import com.amap.api.services.district.DistrictSearchQuery
|
import io.reactivex.Observable
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.schedulers.Schedulers
|
import java.util.*
|
import java.util.concurrent.CopyOnWriteArrayList
|
import kotlin.collections.ArrayList
|
import kotlin.math.*
|
|
/**
|
* @author riku
|
* Date: 2019/5/16
|
* 基类地图activity
|
*/
|
const val GROUP_POINT = "groupPoint"//组合标记点
|
|
abstract class BaseMapActivity : BaseActivity() {
|
|
lateinit var aMap: AMap
|
|
lateinit var mUiSettings: UiSettings
|
|
lateinit var groupBitmapDescriptor: BitmapDescriptor
|
|
val markerIDS = intArrayOf(R.drawable.icon_mark_red, R.drawable.icon_mark_green, R.drawable.icon_mark_orange, R.drawable.icon_mark_purple, R.drawable.icon_mark_blue)
|
|
lateinit var problemMarkerList:ArrayList<Int>
|
|
open var translucent = false
|
|
open var needMerge = true
|
|
private val polylineOptions = PolylineOptions()
|
|
val myLatLngList = CopyOnWriteArrayList<MyLatLng>()//并发容器CopyOnWriteArrayList,防止多线程操作时报错
|
//地图放大等级
|
var zoomLevel = 9F
|
//城市编号
|
var cityCode = "021"
|
//区县编号
|
var districtKeyWord = "浦东区"
|
|
var latitudeCurrent = -1.0
|
var longitudeCurrent = -1.0
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
if (translucent) {
|
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
}
|
}
|
super.onCreate(savedInstanceState)
|
getMapView().onCreate(savedInstanceState)
|
aMap = getMapView().map
|
mUiSettings = aMap.uiSettings
|
groupBitmapDescriptor = BitmapDescriptorFactory.fromResource(R.drawable.icon_mark_blue_sel)
|
|
initMarkPhotoList()
|
onMapInitStart()
|
initMap()
|
}
|
|
override fun onSaveInstanceState(outState: Bundle?) {
|
super.onSaveInstanceState(outState)
|
getMapView().onSaveInstanceState(outState)
|
}
|
|
override fun onResume() {
|
super.onResume()
|
getMapView().onResume()
|
}
|
|
override fun onPause() {
|
super.onPause()
|
getMapView().onPause()
|
}
|
|
override fun onDestroy() {
|
super.onDestroy()
|
getMapView().onDestroy()
|
}
|
|
abstract fun onMapInitStart()
|
|
//初始化带数字marker的列表
|
private fun initMarkPhotoList() {
|
problemMarkerList = ArrayList<Int>().apply {
|
add(R.drawable.icon_mark1_red)
|
add(R.drawable.icon_mark2_red)
|
add(R.drawable.icon_mark3_red)
|
add(R.drawable.icon_mark4_red)
|
add(R.drawable.icon_mark5_red)
|
add(R.drawable.icon_mark6_red)
|
add(R.drawable.icon_mark7_red)
|
add(R.drawable.icon_mark8_red)
|
add(R.drawable.icon_mark9_red)
|
add(R.drawable.icon_mark10_red)
|
add(R.drawable.icon_mark11_red)
|
add(R.drawable.icon_mark12_red)
|
add(R.drawable.icon_mark13_red)
|
add(R.drawable.icon_mark14_red)
|
add(R.drawable.icon_mark15_red)
|
add(R.drawable.icon_mark16_red)
|
add(R.drawable.icon_mark17_red)
|
add(R.drawable.icon_mark18_red)
|
add(R.drawable.icon_mark19_red)
|
add(R.drawable.icon_mark20_red)
|
add(R.drawable.icon_mark21_red)
|
add(R.drawable.icon_mark22_red)
|
add(R.drawable.icon_mark23_red)
|
add(R.drawable.icon_mark24_red)
|
add(R.drawable.icon_mark25_red)
|
add(R.drawable.icon_mark26_red)
|
add(R.drawable.icon_mark27_red)
|
add(R.drawable.icon_mark28_red)
|
add(R.drawable.icon_mark29_red)
|
add(R.drawable.icon_mark30_red)
|
}
|
}
|
|
/**
|
* 初始化高德地图参数
|
*/
|
private var lastTime = 0L//记录最新一次镜头变化回调函数时间
|
|
open fun initMap() {
|
aMap.apply {
|
setOnMarkerClickListener {
|
onMarkerClick(it)
|
return@setOnMarkerClickListener true
|
}
|
|
setOnCameraChangeListener(object : AMap.OnCameraChangeListener {
|
override fun onCameraChangeFinish(p0: CameraPosition?) {
|
//每次镜头缩放后,记录最新的一次缩放的时间
|
lastTime = Date().time
|
val currentTime = lastTime
|
|
Thread(Runnable {
|
//如果在一定时间内秒内没有新的镜头缩放变化,则绘制图标
|
Thread.sleep(250)
|
if (currentTime == lastTime) {
|
p0?.let {
|
if (abs(zoomLevel - it.zoom) > 0.0) {
|
zoomLevel = it.zoom
|
drawMarkers()
|
drawPolyline()
|
}
|
}
|
}
|
}).start()
|
}
|
|
override fun onCameraChange(p0: CameraPosition?) {
|
|
}
|
|
})
|
|
setOnMyLocationChangeListener {
|
latitudeCurrent = it.latitude
|
longitudeCurrent = it.longitude
|
}
|
|
polylineOptions.color(Color.BLUE)
|
polylineOptions.width(3f)
|
addPolyline(polylineOptions)
|
}
|
mUiSettings.apply {
|
isZoomControlsEnabled = true
|
isRotateGesturesEnabled = false
|
}
|
}
|
|
/**
|
* 初始化定位
|
*/
|
open fun initLocation() {
|
zoomLevel = 9F
|
var curDistrictItem = DistrictItem()
|
val mDistrictSearch = DistrictSearch(this).apply {
|
setOnDistrictSearchListener { districtResult ->
|
if (districtResult?.aMapException?.errorCode != com.amap.api.services.core.AMapException.CODE_AMAP_SUCCESS) return@setOnDistrictSearchListener
|
districtResult.district.forEach { item ->
|
if (item.name == districtKeyWord && item.citycode == CommonUtils.getAmapCityCode(cityCode)) {
|
curDistrictItem = item
|
return@forEach
|
}
|
}
|
val mCenterLatLng = curDistrictItem.center
|
curDistrictItem.center.let {
|
zoomLevel = when (zoomLevel.toInt()) {
|
Domain.LEVEL_PROVINCE -> 8F
|
Domain.LEVEL_CITY -> 9F
|
Domain.LEVEL_DISTRICT -> 12F
|
else -> 9F
|
}
|
}
|
aMap.animateCamera(
|
CameraUpdateFactory.newCameraPosition(
|
CameraPosition(LatLng(mCenterLatLng.latitude, mCenterLatLng.longitude), zoomLevel, 0F, 0F)
|
),
|
object : AMap.CancelableCallback {
|
override fun onFinish() {
|
drawBoundary()
|
drawMarkers()
|
}
|
|
override fun onCancel() {
|
drawBoundary()
|
drawMarkers()
|
}
|
}
|
)
|
}
|
}
|
val query = DistrictSearchQuery()
|
query.keywords = districtKeyWord
|
query.isShowBoundary = true
|
aMap.clear()
|
mDistrictSearch.query = query
|
mDistrictSearch.searchDistrictAsyn()
|
}
|
|
/**
|
* 绘制区县边界
|
*/
|
private fun drawBoundary() {
|
|
}
|
|
/**
|
* 绘制标识点
|
*/
|
open fun drawMarkers() {
|
//经纬度集合;图标集合;根据zoom大小合并或分离marker
|
aMap.clear()
|
|
val disposable = Observable.create<MarkerOptions> {emitter ->
|
myLatLngList.forEach { it.groupNo = null }
|
val group = SparseArray<ArrayList<MyLatLng>>()
|
|
if (needMerge) {
|
for (i in myLatLngList.indices) {
|
if (i >= myLatLngList.size) {
|
return@create
|
}
|
val p1 = myLatLngList[i]
|
|
for (y in i + 1 until myLatLngList.size) {
|
val p2 = myLatLngList[y]
|
|
val distance = AMapUtils.calculateLineDistance(p1.latLng, p2.latLng)
|
if (needMerge(distance.toDouble(), zoomLevel)) {
|
val no1 = p1.groupNo
|
val no2 = p2.groupNo
|
|
if (no1 == null && no2 == null) {
|
val index = group.size()
|
p1.groupNo = index
|
p2.groupNo = index
|
group.put(index, ArrayList<MyLatLng>().apply {
|
add(p1)
|
add(p2)
|
})
|
} else if (no1 != null && no2 != null) {
|
//do noting
|
continue
|
} else {
|
val no = no1 ?: no2
|
p1.groupNo = no
|
p2.groupNo = no
|
if (group[no!!]?.contains(p2) == false) {
|
group[no].add(p2)
|
}
|
if (group[no]?.contains(p1) == false) {
|
group[no].add(p1)
|
}
|
}
|
}
|
}
|
}
|
}
|
|
for (i in 0 until group.size()) {
|
val latLng = getCenterP(group[i])
|
emitter.onNext(
|
MarkerOptions().icon(groupBitmapDescriptor).position(latLng).title("${group[i].size}个").snippet(GROUP_POINT)
|
)
|
}
|
myLatLngList.forEach {
|
if (it.groupNo == null) {
|
val bd = BitmapDescriptorFactory.fromResource(it.drawableId ?: R.drawable.icon_mark_blue_sel)
|
emitter.onNext(
|
MarkerOptions().icon(bd).position(it.latLng).title(it.title).snippet(it.snippet).apply {
|
if (!it.selected) {
|
alpha(0.3F)
|
}
|
}
|
)
|
}
|
}
|
emitter.onComplete()
|
}.subscribeOn(Schedulers.io())
|
.observeOn(AndroidSchedulers.mainThread())
|
.subscribe ({
|
val marker = aMap.addMarker(it)
|
if (marker.title.isNotEmpty()) {
|
aMap.addText(
|
TextOptions().zIndex(marker.zIndex).text(marker.title).backgroundColor(Color.TRANSPARENT).fontColor(Color.WHITE).fontSize(24)
|
.position(
|
LatLng(
|
getLat(aMap.scalePerPixel, it.position.latitude),
|
it.position.longitude
|
)
|
)
|
)
|
}
|
}, {
|
MyCrashHandler.instance?.catchException(it)
|
})
|
disposableList.add(disposable)
|
}
|
|
fun drawPolyline(latLng: LatLng) {
|
aMap.addPolyline(polylineOptions.add(latLng))
|
}
|
|
/**
|
* 绘制轨迹
|
*/
|
fun drawPolyline(latLngList: List<LatLng>) {
|
aMap.addPolyline(polylineOptions.addAll(latLngList))
|
}
|
|
private fun drawPolyline(){
|
aMap.addPolyline(polylineOptions)
|
}
|
|
|
//设置地图监听事件
|
abstract fun onMarkerClick(marker: Marker)
|
|
abstract fun getMapView():MapView
|
|
/**
|
* 判断两个坐标点之间的距离在当前放大级别下,是否需要合并为一个点展示
|
* @param distance 距离(米)
|
* @param zoomLevel 放大级别
|
* 缩放级别-比例尺-cameraPosition.zoom:
|
* 19-10m-(19=<zoom<20)
|
* 18-25m-(18=<zoom<19)
|
* 17-50m-(17=<zoom<18)
|
* 16-100m-(16=<zoom<17)
|
* 15-200m-(15=<zoom<16)
|
*14-500m-(14=<zoom<15)
|
*13-1km-(13=<zoom<14)
|
* 12-2km-(12=<zoom<13)
|
* 11-5km-(11=<zoom<12)
|
*10-10km-(10=<zoom<11)
|
*9-20km-(9=<zoom<10)
|
*8-30km-(8=<zoom<9)
|
* 7-50km-(7=<zoom<8)
|
*6-100km-(6=<zoom<7)
|
* 5-200km-(5=<zoom<6)
|
* 4-500km-(4=<zoom<5)
|
* 3-1000km-(3=<zoom<4)
|
*/
|
open fun needMerge(distance: Double, zoomLevel: Float): Boolean {
|
val tmpLevel = when {
|
zoomLevel < 3 -> 3F
|
zoomLevel > 19 -> 19F
|
else -> zoomLevel
|
}
|
val minDistancePerLevel = 1000000 / (2.0.pow((tmpLevel - 3).toDouble()))
|
return distance < minDistancePerLevel * 0.8
|
}
|
|
/**
|
* 获取坐标中心点
|
*/
|
private fun getCenterP(group: ArrayList<MyLatLng>) :LatLng{
|
var x = 0.0
|
var y = 0.0
|
var z = 0.0
|
group.forEach {
|
val lat = it.latLng.latitude * Math.PI / 180
|
val lon = it.latLng.longitude * Math.PI / 180
|
x += cos(lat) * cos(lon)
|
y += cos(lat) * sin(lon)
|
z += sin(lat)
|
}
|
x /= group.size
|
y /= group.size
|
z /= group.size
|
|
val rLon = atan2(y, x)
|
val rHyp = sqrt(x * x + y * y)
|
val rLat = atan2(z, rHyp)
|
|
return LatLng(rLat * 180 / Math.PI, rLon * 180 / Math.PI)
|
}
|
|
|
fun refreshLatLng(title: String, snippet: String, marker: Marker? = null) {
|
if (marker != null) {
|
marker.alpha = if (marker.alpha == 0.3F) 1.0F else 0.3F
|
} else {
|
aMap.mapScreenMarkers.forEach {
|
if (it.snippet == snippet && it.title == title) {
|
it.alpha = if (it.alpha == 0.3F) 1.0F else 0.3F
|
}
|
}
|
}
|
aMap.showMapText(true)
|
myLatLngList.forEach {l ->
|
if (l.snippet == snippet && l.title == title) {
|
l.selected = !l.selected
|
// aMap.animateCamera(
|
// CameraUpdateFactory.newCameraPosition(
|
// CameraPosition(l.latLng, 16F, 45F, 0F)
|
// )
|
// )
|
return
|
}
|
}
|
}
|
|
private fun getLat(scalePerPixel: Float, lat: Double): Double {
|
return 0.00045 * scalePerPixel + lat
|
}
|
|
/**
|
* 辅助类,地图缩放时,需要记录点位所在的合并点序号,以及一些附属信息
|
*/
|
data class MyLatLng(
|
var latLng: LatLng,
|
var title: String = "",
|
var snippet: String = "",
|
var groupNo: Int? = null,
|
var drawableId: Int? = null,
|
var selected: Boolean = false
|
)
|
}
|