开发路径导航功能
This commit is contained in:
43
app/src/main/java/com/navinfo/omqs/bean/NaviRoute.kt
Normal file
43
app/src/main/java/com/navinfo/omqs/bean/NaviRoute.kt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package com.navinfo.omqs.bean
|
||||||
|
|
||||||
|
import com.navinfo.collect.library.data.entity.RenderEntity
|
||||||
|
import com.navinfo.collect.library.utils.GeometryTools
|
||||||
|
import org.oscim.core.GeoPoint
|
||||||
|
|
||||||
|
data class NaviRoute(
|
||||||
|
//我是整条路径中的第几段路径
|
||||||
|
var indexInPath: Int = -1,
|
||||||
|
//link id
|
||||||
|
val linkId: String,
|
||||||
|
//起点id
|
||||||
|
var sNode: String = "",
|
||||||
|
//终点id
|
||||||
|
var eNode: String = "",
|
||||||
|
//方向
|
||||||
|
var direct: Int = 0,
|
||||||
|
//道路名称
|
||||||
|
var name: String = "",
|
||||||
|
//路段总长
|
||||||
|
var length: Double = 0.0,
|
||||||
|
//当前link在整段路径中的起点
|
||||||
|
var startIndexInPath: Int = -1,
|
||||||
|
//当前link在整段路径中的终点
|
||||||
|
var endIndexIntPath: Int = -1,
|
||||||
|
var itemList: MutableList<NaviRouteItem>? = null
|
||||||
|
) {
|
||||||
|
var pointList: MutableList<GeoPoint> = mutableListOf()
|
||||||
|
get() {
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
length = GeometryTools.getDistance(value)
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class NaviRouteItem(
|
||||||
|
var index: Int,
|
||||||
|
val data: RenderEntity,
|
||||||
|
val linkId: String,
|
||||||
|
var distance: Int = -1
|
||||||
|
)
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.navinfo.omqs.bean
|
|
||||||
|
|
||||||
import com.navinfo.collect.library.utils.GeometryTools
|
|
||||||
import com.navinfo.collect.library.utils.GeometryToolsKt
|
|
||||||
import org.locationtech.jts.geom.Geometry
|
|
||||||
import org.oscim.core.GeoPoint
|
|
||||||
|
|
||||||
data class Route(
|
|
||||||
val linkId: String,
|
|
||||||
var sNode: String = "",
|
|
||||||
var eNode: String = "",
|
|
||||||
var direct: Int = 0,
|
|
||||||
var name: String = "",
|
|
||||||
var length: Double = 0.0,
|
|
||||||
) {
|
|
||||||
var pointList: MutableList<GeoPoint> = mutableListOf()
|
|
||||||
get() {
|
|
||||||
return field
|
|
||||||
}
|
|
||||||
set(value) {
|
|
||||||
length = GeometryTools.getDistance(value)
|
|
||||||
field = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -388,8 +388,12 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.listDataMessage.observe(this) {
|
||||||
|
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.liveDataItemList.observe(this) {
|
viewModel.liveDataItemList.observe(this) {
|
||||||
if(it.isNotEmpty()) {
|
if (it.isNotEmpty()) {
|
||||||
if (leftFragment == null || leftFragment !is ItemListFragment) {
|
if (leftFragment == null || leftFragment !is ItemListFragment) {
|
||||||
leftFragment = ItemListFragment {
|
leftFragment = ItemListFragment {
|
||||||
binding.mainActivityLeftFragment.visibility = View.GONE
|
binding.mainActivityLeftFragment.visibility = View.GONE
|
||||||
|
|||||||
@@ -123,6 +123,11 @@ class MainViewModel @Inject constructor(
|
|||||||
*/
|
*/
|
||||||
val liveDataItemList = MutableLiveData<List<RenderEntity>>()
|
val liveDataItemList = MutableLiveData<List<RenderEntity>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提示信息
|
||||||
|
*/
|
||||||
|
val listDataMessage = MutableLiveData<String>()
|
||||||
|
|
||||||
private var traceTag: String = "TRACE_TAG"
|
private var traceTag: String = "TRACE_TAG"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -217,15 +222,15 @@ class MainViewModel @Inject constructor(
|
|||||||
private var currentMapZoomLevel: Int = 0
|
private var currentMapZoomLevel: Int = 0
|
||||||
|
|
||||||
//导航信息
|
//导航信息
|
||||||
private var naviEngine: NaviEngine = NaviEngine()
|
private var naviEngine: NaviEngine? = null
|
||||||
|
|
||||||
|
//规划成功
|
||||||
|
private var naviPathSuccess = false
|
||||||
|
|
||||||
// 定义一个互斥锁
|
// 定义一个互斥锁
|
||||||
private val naviMutex = Mutex()
|
private val naviMutex = Mutex()
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
||||||
|
|
||||||
mapController.mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition ->
|
mapController.mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition ->
|
||||||
when (e) {
|
when (e) {
|
||||||
Map.SCALE_EVENT, Map.MOVE_EVENT, Map.ROTATE_EVENT -> liveDataCenterPoint.value =
|
Map.SCALE_EVENT, Map.MOVE_EVENT, Map.ROTATE_EVENT -> liveDataCenterPoint.value =
|
||||||
@@ -317,45 +322,28 @@ class MainViewModel @Inject constructor(
|
|||||||
MapParamUtils.setTaskId(sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1))
|
MapParamUtils.setTaskId(sharedPreferences.getInt(Constant.SELECT_TASK_ID, -1))
|
||||||
socketServer = SocketServer(mapController, traceDataBase, sharedPreferences)
|
socketServer = SocketServer(mapController, traceDataBase, sharedPreferences)
|
||||||
|
|
||||||
// viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
// naviTestFlow().collect {
|
// naviTestFlow().collect { point ->
|
||||||
// naviMutex.lock()
|
// if (naviPathSuccess) {
|
||||||
// if (naviEngine.geometry != null) {
|
// naviEngine?.let {
|
||||||
// //定义垂线
|
// naviMutex.lock()
|
||||||
// val pointPairDistance = PointPairDistance()
|
// it.bindingRoute(null, point)
|
||||||
// val coordinate = Coordinate(it.longitude, it.latitude)
|
// naviMutex.unlock()
|
||||||
// DistanceToPoint.computeDistance(
|
|
||||||
// naviEngine.geometry,
|
|
||||||
// coordinate,
|
|
||||||
// pointPairDistance
|
|
||||||
// )
|
|
||||||
// if (pointPairDistance.getCoordinate(0) !== null) {
|
|
||||||
// val line = GeometryTools.createLineString(
|
|
||||||
// mutableListOf(
|
|
||||||
// it,
|
|
||||||
// GeoPoint(
|
|
||||||
// pointPairDistance.getCoordinate(0).y,
|
|
||||||
// pointPairDistance.getCoordinate(0).x
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// mapController.lineHandler.showLine(line.toText())
|
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// naviMutex.unlock()
|
|
||||||
// }
|
// }
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun naviTestFlow(): Flow<GeoPoint> = flow {
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
emit(mapController.mMapView.vtmMap.mapPosition.geoPoint)
|
|
||||||
delay(1000)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fun naviTestFlow(): Flow<GeoPoint> = flow {
|
||||||
|
//
|
||||||
|
// while (true) {
|
||||||
|
// emit(mapController.mMapView.vtmMap.mapPosition.geoPoint)
|
||||||
|
// delay(1000)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前任务
|
* 获取当前任务
|
||||||
*/
|
*/
|
||||||
@@ -365,7 +353,7 @@ class MainViewModel @Inject constructor(
|
|||||||
val res = realm.where(TaskBean::class.java).equalTo("id", id).findFirst()
|
val res = realm.where(TaskBean::class.java).equalTo("id", id).findFirst()
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
currentTaskBean = realm.copyFromRealm(res)
|
currentTaskBean = realm.copyFromRealm(res)
|
||||||
planningPath(currentTaskBean!!)
|
// planningPath(currentTaskBean!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,135 +363,44 @@ class MainViewModel @Inject constructor(
|
|||||||
// Toast.makeText(context, "正在计算导航路径", Toast.LENGTH_SHORT).show()
|
// Toast.makeText(context, "正在计算导航路径", Toast.LENGTH_SHORT).show()
|
||||||
viewModelScope.launch(Dispatchers.Default) {
|
viewModelScope.launch(Dispatchers.Default) {
|
||||||
naviMutex.lock()
|
naviMutex.lock()
|
||||||
naviEngine = NaviEngine()
|
naviEngine = NaviEngine(
|
||||||
val pathList = mutableListOf<Route>()
|
niMapController = mapController,
|
||||||
val realm = Realm.getDefaultInstance()
|
callback = object : OnNaviEngineCallbackListener {
|
||||||
for (link in taskBean.hadLinkDvoList) {
|
override fun planningPathSuccess() {
|
||||||
//测线不参与导航
|
naviPathSuccess = true
|
||||||
if (link.linkStatus == 3) {
|
listDataMessage.postValue("导航路径规划完成")
|
||||||
continue
|
}
|
||||||
}
|
|
||||||
val route = Route(
|
|
||||||
linkId = link.linkPid,
|
|
||||||
)
|
|
||||||
route.pointList = GeometryTools.getGeoPoints(link.geometry)
|
|
||||||
//查询每条link的snode,enode
|
|
||||||
val res1 = realm.where(RenderEntity::class.java)
|
|
||||||
.equalTo("table", DataCodeEnum.OMDB_RD_LINK.name).and()
|
|
||||||
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
|
||||||
res1?.let {
|
|
||||||
|
|
||||||
val snodePid = it.properties["snodePid"]
|
override fun planningPathError(errorCode: Int, errorMessage: String) {
|
||||||
if (snodePid != null) {
|
naviPathSuccess = false
|
||||||
route.sNode = snodePid
|
listDataMessage.postValue(errorMessage)
|
||||||
}
|
}
|
||||||
val enodePid = it.properties["enodePid"]
|
|
||||||
if (enodePid != null) {
|
override fun bindingResults(list: List<NaviRouteItem>) {
|
||||||
route.eNode = enodePid
|
val signList = mutableListOf<SignBean>()
|
||||||
}
|
for (naviRouteItem in list) {
|
||||||
}
|
val signBean = SignBean(
|
||||||
//查询每条link的方向
|
iconId = SignUtil.getSignIcon(naviRouteItem.data),
|
||||||
val res2 = realm.where(RenderEntity::class.java)
|
iconText = SignUtil.getSignIconText(naviRouteItem.data),
|
||||||
.equalTo("table", DataCodeEnum.OMDB_LINK_DIRECT.name).and()
|
linkId = naviRouteItem.linkId,
|
||||||
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
distance = naviRouteItem.distance,
|
||||||
res2?.let {
|
name = SignUtil.getSignNameText(naviRouteItem.data),
|
||||||
val direct = it.properties["direct"]
|
bottomRightText = SignUtil.getSignBottomRightText(naviRouteItem.data),
|
||||||
if (direct != null) {
|
renderEntity = naviRouteItem.data,
|
||||||
route.direct = direct.toInt()
|
isMoreInfo = SignUtil.isMoreInfo(naviRouteItem.data),
|
||||||
}
|
index = SignUtil.getRoadInfoIndex(naviRouteItem.data)
|
||||||
}
|
)
|
||||||
//查询每条link的名称
|
signList.add(signBean)
|
||||||
val res3 = realm.where(RenderEntity::class.java)
|
|
||||||
.equalTo("table", DataCodeEnum.OMDB_LINK_NAME.name).and()
|
|
||||||
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
|
||||||
res3?.let {
|
|
||||||
route.name = "${it.properties["name"]}"
|
|
||||||
}
|
|
||||||
pathList.add(route)
|
|
||||||
}
|
|
||||||
//用来存储最终的导航路径
|
|
||||||
val newRouteList = mutableListOf<Route>()
|
|
||||||
//比对路径排序用的
|
|
||||||
val tempRouteList = pathList.toMutableList()
|
|
||||||
//先找到一根有方向的link,确定起终点
|
|
||||||
var routeStart: Route? = null
|
|
||||||
for (i in tempRouteList.indices) {
|
|
||||||
val route = pathList[i]
|
|
||||||
//只要时单方向的就行
|
|
||||||
if (route.direct == 2 || route.direct == 3) {
|
|
||||||
routeStart = route
|
|
||||||
tempRouteList.removeAt(i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (routeStart != null) {
|
|
||||||
var sNode = ""
|
|
||||||
var eNode = ""
|
|
||||||
//如果snode,enode是顺方向,geometry 不动,否则反转
|
|
||||||
if (routeStart.direct == 3) {
|
|
||||||
routeStart.pointList.reverse()
|
|
||||||
sNode = routeStart.eNode
|
|
||||||
eNode = routeStart.sNode
|
|
||||||
} else {
|
|
||||||
sNode = routeStart.sNode
|
|
||||||
eNode = routeStart.eNode
|
|
||||||
}
|
|
||||||
newRouteList.add(routeStart)
|
|
||||||
var bBreak = true
|
|
||||||
while (bBreak) {
|
|
||||||
//先找其实link的后续link
|
|
||||||
var bHasNext = false
|
|
||||||
for (route in tempRouteList) {
|
|
||||||
//如果是link 的e 对下个link的s,方向不用动,否则下个link的geometry反转
|
|
||||||
if (route.sNode != "" && eNode == route.sNode) {
|
|
||||||
newRouteList.add(route)
|
|
||||||
tempRouteList.remove(route)
|
|
||||||
eNode = route.eNode
|
|
||||||
bHasNext = true
|
|
||||||
break
|
|
||||||
} else if (route.eNode != "" && eNode == route.eNode) {
|
|
||||||
route.pointList.reverse()
|
|
||||||
newRouteList.add(route)
|
|
||||||
tempRouteList.remove(route)
|
|
||||||
eNode = route.sNode
|
|
||||||
bHasNext = true
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
liveDataSignList.postValue(signList)
|
||||||
}
|
}
|
||||||
//先找其实link的起始link
|
})
|
||||||
var bHasLast = false
|
listDataMessage.postValue("开始导航路径规划")
|
||||||
for (route in tempRouteList) {
|
naviEngine!!.planningPath(taskBean)
|
||||||
//如果是link 的s 对上个link的e,方向不用动,否则下个link的geometry反转
|
|
||||||
if (route.eNode != "" && sNode == route.eNode) {
|
|
||||||
newRouteList.add(0, route)
|
|
||||||
tempRouteList.remove(route)
|
|
||||||
sNode = route.sNode
|
|
||||||
bHasLast = true
|
|
||||||
break
|
|
||||||
} else if (route.sNode != "" && sNode == route.sNode) {
|
|
||||||
route.pointList.reverse()
|
|
||||||
newRouteList.add(0, route)
|
|
||||||
tempRouteList.remove(route)
|
|
||||||
sNode = route.eNode
|
|
||||||
bHasLast = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tempRouteList.size == 0) {
|
|
||||||
bBreak = false
|
|
||||||
} else {
|
|
||||||
if (!bHasLast && !bHasNext) {
|
|
||||||
bBreak = false
|
|
||||||
//TODO 处理错误,路径不完整
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
naviEngine.routeList = newRouteList
|
|
||||||
naviMutex.unlock()
|
naviMutex.unlock()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Toast.makeText(context, "数据未安装,无法计算导航路径", Toast.LENGTH_SHORT).show()
|
listDataMessage.postValue("数据未安装,无法计算导航路径")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,14 +617,9 @@ class MainViewModel @Inject constructor(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val distance = GeometryTools.distanceToDouble(
|
|
||||||
point, GeometryTools.createGeoPoint(element.geometry)
|
|
||||||
)
|
|
||||||
|
|
||||||
val signBean = SignBean(
|
val signBean = SignBean(
|
||||||
iconId = SignUtil.getSignIcon(element),
|
iconId = SignUtil.getSignIcon(element),
|
||||||
iconText = SignUtil.getSignIconText(element),
|
iconText = SignUtil.getSignIconText(element),
|
||||||
distance = distance.toInt(),
|
|
||||||
linkId = linkId,
|
linkId = linkId,
|
||||||
name = SignUtil.getSignNameText(element),
|
name = SignUtil.getSignNameText(element),
|
||||||
bottomRightText = SignUtil.getSignBottomRightText(element),
|
bottomRightText = SignUtil.getSignBottomRightText(element),
|
||||||
@@ -735,7 +627,7 @@ class MainViewModel @Inject constructor(
|
|||||||
isMoreInfo = SignUtil.isMoreInfo(element),
|
isMoreInfo = SignUtil.isMoreInfo(element),
|
||||||
index = SignUtil.getRoadInfoIndex(element)
|
index = SignUtil.getRoadInfoIndex(element)
|
||||||
)
|
)
|
||||||
Log.e("jingo", "捕捉到的数据code ${element.code}")
|
// Log.e("jingo", "捕捉到的数据code ${element.code}")
|
||||||
when (element.code) {
|
when (element.code) {
|
||||||
DataCodeEnum.OMDB_MULTI_DIGITIZED.code,//上下线分离
|
DataCodeEnum.OMDB_MULTI_DIGITIZED.code,//上下线分离
|
||||||
DataCodeEnum.OMDB_CON_ACCESS.code,//全封闭
|
DataCodeEnum.OMDB_CON_ACCESS.code,//全封闭
|
||||||
@@ -864,6 +756,7 @@ class MainViewModel @Inject constructor(
|
|||||||
*/
|
*/
|
||||||
fun onClickLocationButton() {
|
fun onClickLocationButton() {
|
||||||
mapController.locationLayerHandler.animateToCurrentPosition()
|
mapController.locationLayerHandler.animateToCurrentPosition()
|
||||||
|
planningPath(currentTaskBean!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -872,6 +765,7 @@ class MainViewModel @Inject constructor(
|
|||||||
fun onClickMenu() {
|
fun onClickMenu() {
|
||||||
menuState = !menuState
|
menuState = !menuState
|
||||||
liveDataMenuState.postValue(menuState)
|
liveDataMenuState.postValue(menuState)
|
||||||
|
naviEngine!!.bindingRoute(null, mapController.mMapView.vtmMap.mapPosition.geoPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
@@ -1004,7 +898,7 @@ class MainViewModel @Inject constructor(
|
|||||||
* */
|
* */
|
||||||
fun refreshOMDBLayer(layerConfigList: List<ImportConfig>) {
|
fun refreshOMDBLayer(layerConfigList: List<ImportConfig>) {
|
||||||
// 根据获取到的配置信息,筛选未勾选的图层名称
|
// 根据获取到的配置信息,筛选未勾选的图层名称
|
||||||
if (layerConfigList != null && !layerConfigList.isEmpty()) {
|
if (layerConfigList != null && layerConfigList.isNotEmpty()) {
|
||||||
val omdbVisibleList = mutableListOf<String>()
|
val omdbVisibleList = mutableListOf<String>()
|
||||||
layerConfigList.forEach {
|
layerConfigList.forEach {
|
||||||
omdbVisibleList.addAll(it.tableMap.filter { entry ->
|
omdbVisibleList.addAll(it.tableMap.filter { entry ->
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) :
|
|||||||
} else {
|
} else {
|
||||||
bd.signMainInfo.visibility = View.GONE
|
bd.signMainInfo.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
bd.signDistanceText.text = "${item.distance}米"
|
||||||
bd.signSecondIcon.text = ""
|
bd.signSecondIcon.text = ""
|
||||||
if (item.renderEntity.code == DataCodeEnum.OMDB_SPEEDLIMIT.code) {
|
if (item.renderEntity.code == DataCodeEnum.OMDB_SPEEDLIMIT.code) {
|
||||||
val minSpeed = SignUtil.getSpeedLimitMinText(item.renderEntity)
|
val minSpeed = SignUtil.getSpeedLimitMinText(item.renderEntity)
|
||||||
|
|||||||
@@ -12,18 +12,15 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
|
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
|
||||||
import com.navinfo.collect.library.data.entity.*
|
import com.navinfo.collect.library.data.entity.*
|
||||||
import com.navinfo.collect.library.enums.DataCodeEnum
|
|
||||||
import com.navinfo.collect.library.map.NIMapController
|
import com.navinfo.collect.library.map.NIMapController
|
||||||
import com.navinfo.collect.library.map.OnGeoPointClickListener
|
import com.navinfo.collect.library.map.OnGeoPointClickListener
|
||||||
import com.navinfo.collect.library.utils.GeometryTools
|
import com.navinfo.collect.library.utils.GeometryTools
|
||||||
import com.navinfo.collect.library.utils.MapParamUtils
|
import com.navinfo.collect.library.utils.MapParamUtils
|
||||||
import com.navinfo.omqs.Constant
|
import com.navinfo.omqs.Constant
|
||||||
import com.navinfo.omqs.bean.Route
|
|
||||||
import com.navinfo.omqs.db.RealmOperateHelper
|
import com.navinfo.omqs.db.RealmOperateHelper
|
||||||
import com.navinfo.omqs.http.NetResult
|
import com.navinfo.omqs.http.NetResult
|
||||||
import com.navinfo.omqs.http.NetworkService
|
import com.navinfo.omqs.http.NetworkService
|
||||||
import com.navinfo.omqs.tools.FileManager
|
import com.navinfo.omqs.tools.FileManager
|
||||||
import com.navinfo.omqs.ui.activity.login.LoginStatus
|
|
||||||
import com.navinfo.omqs.ui.dialog.FirstDialog
|
import com.navinfo.omqs.ui.dialog.FirstDialog
|
||||||
import com.navinfo.omqs.util.DateTimeUtil
|
import com.navinfo.omqs.util.DateTimeUtil
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
|||||||
@@ -1,25 +1,626 @@
|
|||||||
package com.navinfo.omqs.util
|
package com.navinfo.omqs.util
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.navinfo.collect.library.data.entity.NiLocation
|
||||||
|
import com.navinfo.collect.library.data.entity.RenderEntity
|
||||||
|
import com.navinfo.collect.library.data.entity.TaskBean
|
||||||
|
import com.navinfo.collect.library.enums.DataCodeEnum
|
||||||
|
import com.navinfo.collect.library.map.NIMapController
|
||||||
import com.navinfo.collect.library.utils.GeometryTools
|
import com.navinfo.collect.library.utils.GeometryTools
|
||||||
import com.navinfo.omqs.bean.Route
|
import com.navinfo.omqs.bean.NaviRoute
|
||||||
|
import com.navinfo.omqs.bean.NaviRouteItem
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmQuery
|
||||||
import org.locationtech.jts.geom.LineString
|
import org.locationtech.jts.geom.LineString
|
||||||
|
import org.locationtech.jts.geom.Point
|
||||||
import org.oscim.core.GeoPoint
|
import org.oscim.core.GeoPoint
|
||||||
|
|
||||||
class NaviEngine {
|
public interface OnNaviEngineCallbackListener {
|
||||||
|
fun planningPathSuccess()
|
||||||
|
fun planningPathError(errorCode: Int, errorMessage: String)
|
||||||
|
fun bindingResults(list: List<NaviRouteItem>)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class NaviEngine(val niMapController: NIMapController, val callback: OnNaviEngineCallbackListener) {
|
||||||
|
|
||||||
|
|
||||||
|
private val QUERY_KEY_LIST = arrayOf(
|
||||||
|
DataCodeEnum.OMDB_SPEEDLIMIT.name,
|
||||||
|
DataCodeEnum.OMDB_SPEEDLIMIT_COND.name,
|
||||||
|
DataCodeEnum.OMDB_SPEEDLIMIT_VAR.name,
|
||||||
|
DataCodeEnum.OMDB_TRAFFICLIGHT.name,
|
||||||
|
DataCodeEnum.OMDB_RESTRICTION.name,
|
||||||
|
DataCodeEnum.OMDB_LANEINFO.name,
|
||||||
|
DataCodeEnum.OMDB_TRAFFIC_SIGN.name,
|
||||||
|
DataCodeEnum.OMDB_WARNINGSIGN.name,
|
||||||
|
DataCodeEnum.OMDB_TOLLGATE.name
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 偏离距离 单位:米
|
||||||
|
*/
|
||||||
|
private val DEVIATION_DISTANCE = 150000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 偏离次数上限
|
||||||
|
*/
|
||||||
|
private val DEVIATION_COUNT = 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 局部匹配时,走过的路段还记录100米
|
||||||
|
*/
|
||||||
|
private val PASSED_ROUTE_DISTANCE = 100
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 局部匹配时,没走过的路段还记录1000米
|
||||||
|
*/
|
||||||
|
private val NEXT_ROUTE_DISTANCE = 1000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最远显示距离 米
|
||||||
|
*/
|
||||||
|
private val FARTHEST_DISPLAY_DISTANCE = 550
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定失败次数
|
||||||
|
*/
|
||||||
|
private var errorCount = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前邦定的那段route
|
||||||
|
*/
|
||||||
|
private var routeIndex = -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前绑定的link上哪个point
|
||||||
|
*/
|
||||||
|
private var footIndex = -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定的垂足坐标
|
||||||
|
*/
|
||||||
|
private var footPoint: GeoPoint? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上一次定位绑到路线的距离
|
||||||
|
*/
|
||||||
|
private var lastDistance = -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 整条路的几何
|
||||||
|
*/
|
||||||
var geometry: LineString? = null
|
var geometry: LineString? = null
|
||||||
var routeList = mutableListOf<Route>()
|
|
||||||
|
/**
|
||||||
|
* 临时路径
|
||||||
|
*/
|
||||||
|
var tempGeometry: LineString? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定位点集合
|
||||||
|
*/
|
||||||
|
private var locationList: MutableList<NiLocation> = mutableListOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 局部匹配时的路段
|
||||||
|
*/
|
||||||
|
var tempRoutList = mutableListOf<NaviRoute>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所有路段集合
|
||||||
|
*/
|
||||||
|
var routeList = mutableListOf<NaviRoute>()
|
||||||
get() {
|
get() {
|
||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
val list = mutableListOf<GeoPoint>()
|
val list = mutableListOf<GeoPoint>()
|
||||||
list.addAll(value[0].pointList)
|
val fRoute = value[0]
|
||||||
|
//第一个路段加入
|
||||||
|
list.addAll(fRoute.pointList)
|
||||||
|
//起始点位置
|
||||||
|
fRoute.startIndexInPath = 0
|
||||||
|
var startPoint = fRoute.pointList.size - 1
|
||||||
|
//终点位置
|
||||||
|
fRoute.endIndexIntPath = startPoint
|
||||||
|
fRoute.indexInPath = 0
|
||||||
|
|
||||||
for (i in 1 until value.size) {
|
for (i in 1 until value.size) {
|
||||||
val list2 = value[i].pointList
|
val route = value[i]
|
||||||
|
route.startIndexInPath = startPoint
|
||||||
|
if (route.itemList != null) {
|
||||||
|
for (naviItem in route.itemList!!) {
|
||||||
|
naviItem.index += startPoint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startPoint += route.pointList.size - 1
|
||||||
|
route.endIndexIntPath = startPoint
|
||||||
|
route.indexInPath = i
|
||||||
|
val list2 = ArrayList(route.pointList.toList())
|
||||||
list2.removeAt(0)
|
list2.removeAt(0)
|
||||||
list.addAll(list2)
|
list.addAll(list2)
|
||||||
}
|
}
|
||||||
geometry = GeometryTools.createLineString(list)
|
geometry = GeometryTools.createLineString(list)
|
||||||
field = value
|
field = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算路径
|
||||||
|
*/
|
||||||
|
suspend fun planningPath(taskBean: TaskBean) {
|
||||||
|
|
||||||
|
val pathList = mutableListOf<NaviRoute>()
|
||||||
|
val realm = Realm.getDefaultInstance()
|
||||||
|
for (link in taskBean.hadLinkDvoList) {
|
||||||
|
//测线不参与导航
|
||||||
|
if (link.linkStatus == 3) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val route = NaviRoute(
|
||||||
|
linkId = link.linkPid,
|
||||||
|
)
|
||||||
|
|
||||||
|
route.pointList = GeometryTools.getGeoPoints(link.geometry)
|
||||||
|
//查询每条link的snode,enode
|
||||||
|
val res1 = realm.where(RenderEntity::class.java)
|
||||||
|
.equalTo("table", DataCodeEnum.OMDB_RD_LINK.name).and()
|
||||||
|
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
||||||
|
res1?.let {
|
||||||
|
|
||||||
|
val snodePid = it.properties["snodePid"]
|
||||||
|
if (snodePid != null) {
|
||||||
|
route.sNode = snodePid
|
||||||
|
}
|
||||||
|
val enodePid = it.properties["enodePid"]
|
||||||
|
if (enodePid != null) {
|
||||||
|
route.eNode = enodePid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//查询每条link的方向
|
||||||
|
val res2 = realm.where(RenderEntity::class.java)
|
||||||
|
.equalTo("table", DataCodeEnum.OMDB_LINK_DIRECT.name).and()
|
||||||
|
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
||||||
|
res2?.let {
|
||||||
|
val direct = it.properties["direct"]
|
||||||
|
if (direct != null) {
|
||||||
|
route.direct = direct.toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//查询每条link的名称
|
||||||
|
val res3 = realm.where(RenderEntity::class.java)
|
||||||
|
.equalTo("table", DataCodeEnum.OMDB_LINK_NAME.name).and()
|
||||||
|
.equalTo("properties['linkPid']", link.linkPid).findFirst()
|
||||||
|
res3?.let {
|
||||||
|
route.name = "${it.properties["name"]}"
|
||||||
|
}
|
||||||
|
pathList.add(route)
|
||||||
|
}
|
||||||
|
//用来存储最终的导航路径
|
||||||
|
val newRouteList = mutableListOf<NaviRoute>()
|
||||||
|
//比对路径排序用的
|
||||||
|
val tempRouteList = pathList.toMutableList()
|
||||||
|
//先找到一根有方向的link,确定起终点
|
||||||
|
var routeStart: NaviRoute? = null
|
||||||
|
for (i in tempRouteList.indices) {
|
||||||
|
val route = pathList[i]
|
||||||
|
//只要时单方向的就行
|
||||||
|
if (route.direct == 2 || route.direct == 3) {
|
||||||
|
routeStart = route
|
||||||
|
tempRouteList.removeAt(i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (routeStart != null) {
|
||||||
|
var sNode = ""
|
||||||
|
var eNode = ""
|
||||||
|
//如果sNode,eNode是顺方向,geometry 不动,否则反转
|
||||||
|
if (routeStart.direct == 3) {
|
||||||
|
routeStart.pointList.reverse()
|
||||||
|
sNode = routeStart.eNode
|
||||||
|
eNode = routeStart.sNode
|
||||||
|
} else {
|
||||||
|
sNode = routeStart.sNode
|
||||||
|
eNode = routeStart.eNode
|
||||||
|
}
|
||||||
|
newRouteList.add(routeStart)
|
||||||
|
var bBreak = true
|
||||||
|
while (bBreak) {
|
||||||
|
//先找其实link的后续link
|
||||||
|
var bHasNext = false
|
||||||
|
for (route in tempRouteList) {
|
||||||
|
//如果是link 的e 对下个link的s,方向不用动,否则下个link的geometry反转
|
||||||
|
if (route.sNode != "" && eNode == route.sNode) {
|
||||||
|
newRouteList.add(route)
|
||||||
|
tempRouteList.remove(route)
|
||||||
|
eNode = route.eNode
|
||||||
|
bHasNext = true
|
||||||
|
break
|
||||||
|
} else if (route.eNode != "" && eNode == route.eNode) {
|
||||||
|
route.pointList.reverse()
|
||||||
|
newRouteList.add(route)
|
||||||
|
tempRouteList.remove(route)
|
||||||
|
eNode = route.sNode
|
||||||
|
bHasNext = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//先找其实link的起始link
|
||||||
|
var bHasLast = false
|
||||||
|
for (route in tempRouteList) {
|
||||||
|
//如果是link 的s 对上个link的e,方向不用动,否则下个link的geometry反转
|
||||||
|
if (route.eNode != "" && sNode == route.eNode) {
|
||||||
|
newRouteList.add(0, route)
|
||||||
|
tempRouteList.remove(route)
|
||||||
|
sNode = route.sNode
|
||||||
|
bHasLast = true
|
||||||
|
break
|
||||||
|
} else if (route.sNode != "" && sNode == route.sNode) {
|
||||||
|
route.pointList.reverse()
|
||||||
|
newRouteList.add(0, route)
|
||||||
|
tempRouteList.remove(route)
|
||||||
|
sNode = route.eNode
|
||||||
|
bHasLast = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tempRouteList.size == 0) {
|
||||||
|
bBreak = false
|
||||||
|
} else {
|
||||||
|
if (!bHasLast && !bHasNext) {
|
||||||
|
bBreak = false
|
||||||
|
callback.planningPathError(1, "路径不连通!")
|
||||||
|
realm.close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val itemMap: MutableMap<GeoPoint, MutableList<RenderEntity>> = mutableMapOf()
|
||||||
|
//查询每根link上的关联要素
|
||||||
|
for (route in newRouteList) {
|
||||||
|
//常规点限速
|
||||||
|
var res = realm.where(RenderEntity::class.java)
|
||||||
|
.equalTo("properties['linkPid']", route.linkId).and().`in`(
|
||||||
|
"table",
|
||||||
|
QUERY_KEY_LIST
|
||||||
|
).findAll()
|
||||||
|
if (res != null) {
|
||||||
|
Log.e("jingo", "道路查询预警要素 ${route.linkId} ${res.size}条数据")
|
||||||
|
for (r in res) {
|
||||||
|
Log.e("jingo", "道路查询预警要素 ${r.name}")
|
||||||
|
insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// //条件点限速
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_SPEEDLIMIT_COND.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //可变点限速
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_SPEEDLIMIT_VAR.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //交通灯
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_TRAFFICLIGHT.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //普通交限
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_RESTRICTION.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //车信
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_LANEINFO.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //交通标牌
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_TRAFFIC_SIGN.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //警示信息
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_WARNINGSIGN.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
// //OMDB_TOLLGATE
|
||||||
|
// res = realm.where(RenderEntity::class.java)
|
||||||
|
// .equalTo("table", DataCodeEnum.OMDB_TOLLGATE.name).and()
|
||||||
|
// .equalTo("properties['linkPid']", route.linkId).findAll()
|
||||||
|
// if(res != null){
|
||||||
|
// for(r in res)
|
||||||
|
// insertItemToRoute(realm, route, r, itemMap)
|
||||||
|
// }
|
||||||
|
//对路径上的要素进行排序
|
||||||
|
if (itemMap.isNotEmpty()) {
|
||||||
|
route.itemList = mutableListOf()
|
||||||
|
for (i in route.pointList.indices) {
|
||||||
|
val point = route.pointList[i]
|
||||||
|
if (itemMap.containsKey(point)) {
|
||||||
|
val rEList = itemMap[point]
|
||||||
|
for (item in rEList!!) {
|
||||||
|
val naviRouteItem = NaviRouteItem(i, item, route.linkId)
|
||||||
|
route.itemList!!.add(naviRouteItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route.itemList!!.sortBy { it.index }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
realm.close()
|
||||||
|
routeList = newRouteList
|
||||||
|
callback.planningPathSuccess()
|
||||||
|
niMapController.lineHandler.showLine(geometry!!.toText())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将要素绑定到路径上
|
||||||
|
*/
|
||||||
|
private fun insertItemToRoute(
|
||||||
|
realm: Realm,
|
||||||
|
route: NaviRoute,
|
||||||
|
res: RenderEntity?,
|
||||||
|
itemMap: MutableMap<GeoPoint, MutableList<RenderEntity>>
|
||||||
|
) {
|
||||||
|
if (res != null) {
|
||||||
|
val geometry = GeometryTools.createGeometry(res.geometry)
|
||||||
|
if (geometry is Point) {
|
||||||
|
//获取一个垂足点
|
||||||
|
val footAndDistance = GeometryTools.pointToLineDistance(
|
||||||
|
GeoPoint(
|
||||||
|
geometry.coordinate.y, geometry.coordinate.x
|
||||||
|
), GeometryTools.createLineString(route.pointList)
|
||||||
|
)
|
||||||
|
val point = GeoPoint(
|
||||||
|
footAndDistance.getCoordinate(0).y, footAndDistance.getCoordinate(0).x
|
||||||
|
)
|
||||||
|
niMapController.markerHandle.addMarker(point, res.id, res.name)
|
||||||
|
route.pointList.add(footAndDistance.footIndex + 1, point)
|
||||||
|
if (itemMap.containsKey(point)) {
|
||||||
|
itemMap[point]!!.add(realm.copyFromRealm(res))
|
||||||
|
} else {
|
||||||
|
itemMap[point] = mutableListOf(realm.copyFromRealm(res))
|
||||||
|
}
|
||||||
|
} else if (geometry is LineString) {
|
||||||
|
//如果是线型数据,取路径的最后一个点
|
||||||
|
val endPoint = route.pointList.last()
|
||||||
|
if (itemMap.containsKey(endPoint)) {
|
||||||
|
itemMap[endPoint]!!.add(realm.copyFromRealm(res))
|
||||||
|
} else {
|
||||||
|
itemMap[endPoint] = mutableListOf(realm.copyFromRealm(res))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定道路
|
||||||
|
*/
|
||||||
|
fun bindingRoute(location: NiLocation?, point: GeoPoint) {
|
||||||
|
if (geometry != null) {
|
||||||
|
//还没有绑定到路径的时候
|
||||||
|
if (routeIndex < 0) {
|
||||||
|
val pointPairDistance = GeometryTools.pointToLineDistance(point, geometry)
|
||||||
|
//定义垂线
|
||||||
|
//定位点到垂足距离不超过30米
|
||||||
|
if (pointPairDistance.getMeterDistance() < DEVIATION_DISTANCE) {
|
||||||
|
footIndex = pointPairDistance.footIndex
|
||||||
|
Log.e(
|
||||||
|
"jingo",
|
||||||
|
"当前绑定到了整条路线的第 $footIndex 点 ${pointPairDistance.getMeterDistance()} "
|
||||||
|
)
|
||||||
|
val lastRouteIndex = routeIndex
|
||||||
|
for (i in routeList.indices) {
|
||||||
|
val route = routeList[i]
|
||||||
|
if (route.startIndexInPath <= footIndex && route.endIndexIntPath >= footIndex) {
|
||||||
|
routeIndex = route.indexInPath
|
||||||
|
Log.e(
|
||||||
|
"jingo",
|
||||||
|
"当前绑定到了整条路线id ${route.linkId} "
|
||||||
|
)
|
||||||
|
niMapController.lineHandler.showLine(route.pointList)
|
||||||
|
footPoint = GeoPoint(
|
||||||
|
pointPairDistance.getCoordinate(0).y,
|
||||||
|
pointPairDistance.getCoordinate(0).x
|
||||||
|
)
|
||||||
|
val listPoint = mutableListOf(point, footPoint!!)
|
||||||
|
niMapController.lineHandler.showLine(
|
||||||
|
listPoint
|
||||||
|
)
|
||||||
|
|
||||||
|
if (lastRouteIndex != routeIndex) {
|
||||||
|
createTempPath()
|
||||||
|
}
|
||||||
|
matchingItem()
|
||||||
|
errorCount = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deviationUp()
|
||||||
|
}
|
||||||
|
} else if (tempGeometry != null && tempRoutList.isNotEmpty()) {
|
||||||
|
val pointPairDistance = GeometryTools.pointToLineDistance(point, tempGeometry)
|
||||||
|
//定义垂线
|
||||||
|
//定位点到垂足距离不超过30米
|
||||||
|
if (pointPairDistance.getMeterDistance() < DEVIATION_DISTANCE) {
|
||||||
|
footIndex = pointPairDistance.footIndex + tempRoutList[0].startIndexInPath
|
||||||
|
Log.e("jingo", "局部 当前绑定到了整条路线的第 $footIndex 点")
|
||||||
|
val lastRouteIndex = routeIndex
|
||||||
|
for (i in tempRoutList.indices) {
|
||||||
|
val route = tempRoutList[i]
|
||||||
|
if (route.startIndexInPath <= footIndex && route.endIndexIntPath >= footIndex) {
|
||||||
|
routeIndex = route.indexInPath
|
||||||
|
Log.e(
|
||||||
|
"jingo",
|
||||||
|
"局部 当前绑定到了整条路线id ${route.linkId} "
|
||||||
|
)
|
||||||
|
niMapController.lineHandler.showLine(route.pointList)
|
||||||
|
footPoint = GeoPoint(
|
||||||
|
pointPairDistance.getCoordinate(0).y,
|
||||||
|
pointPairDistance.getCoordinate(0).x
|
||||||
|
)
|
||||||
|
|
||||||
|
val listPoint = mutableListOf(point, footPoint!!)
|
||||||
|
niMapController.lineHandler.showLine(
|
||||||
|
listPoint
|
||||||
|
)
|
||||||
|
|
||||||
|
if (lastRouteIndex != routeIndex) {
|
||||||
|
createTempPath()
|
||||||
|
}
|
||||||
|
matchingItem()
|
||||||
|
errorCount = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deviationUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配要素
|
||||||
|
* @point:定位点
|
||||||
|
*/
|
||||||
|
private fun matchingItem() {
|
||||||
|
if (routeIndex > -1 && tempRoutList.isNotEmpty() && tempGeometry != null) {
|
||||||
|
//道路前方一定距离范围内的要素信息
|
||||||
|
val bindingItemList = mutableListOf<NaviRouteItem>()
|
||||||
|
//临时局部路径的游标对应整条路径的游标
|
||||||
|
val tempFootIndex = footIndex + tempRoutList[0].startIndexInPath
|
||||||
|
//定位点到要素的路径距离
|
||||||
|
var distance = 0.0
|
||||||
|
//计算要素路径距离的点集合
|
||||||
|
val disPoints = mutableListOf(footPoint!!)
|
||||||
|
//下一个要素的起点游标
|
||||||
|
var tempIndex = footIndex + 1
|
||||||
|
for(route in tempRoutList) {
|
||||||
|
if( route.indexInPath < routeIndex)
|
||||||
|
continue
|
||||||
|
if (route.itemList != null && route.itemList!!.isNotEmpty()) {
|
||||||
|
for (naviItem in route.itemList!!) {
|
||||||
|
if (naviItem.index > tempFootIndex) {
|
||||||
|
val rightI = naviItem.index - tempRoutList[0].startIndexInPath + 1
|
||||||
|
for (i in tempIndex until rightI) {
|
||||||
|
val geo = tempGeometry!!.coordinates[i]
|
||||||
|
disPoints.add(GeoPoint(geo.y, geo.x))
|
||||||
|
}
|
||||||
|
tempIndex = rightI
|
||||||
|
distance = GeometryTools.getDistance(disPoints)
|
||||||
|
if (distance < FARTHEST_DISPLAY_DISTANCE && distance > -1) {
|
||||||
|
naviItem.distance = distance.toInt()
|
||||||
|
bindingItemList.add(naviItem)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(distance >= FARTHEST_DISPLAY_DISTANCE){
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback.bindingResults(bindingItemList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建临时局部路径
|
||||||
|
*/
|
||||||
|
private fun createTempPath() {
|
||||||
|
tempRoutList.clear()
|
||||||
|
tempGeometry = null
|
||||||
|
if (routeIndex > -1 && routeIndex < routeList.size && footPoint != null) {
|
||||||
|
val route = routeList[routeIndex]
|
||||||
|
//当前垂足点在这个路段中是第几个坐标
|
||||||
|
tempRoutList.add(route)
|
||||||
|
var distance = 0.0
|
||||||
|
//已经走过的路是否有100米
|
||||||
|
var i = routeIndex - 1
|
||||||
|
while (i >= 0 && distance < PASSED_ROUTE_DISTANCE) {
|
||||||
|
val routeT = routeList[i]
|
||||||
|
tempRoutList.add(0, routeT)
|
||||||
|
distance += routeT.length
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
distance = 0.0
|
||||||
|
//没走过的路是否有1000米
|
||||||
|
var j = routeIndex + 1
|
||||||
|
while (j < routeList.size && distance < NEXT_ROUTE_DISTANCE) {
|
||||||
|
val routeT = routeList[j]
|
||||||
|
tempRoutList.add(routeT)
|
||||||
|
distance += routeT.length
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val list = mutableListOf<GeoPoint>()
|
||||||
|
val fRoute = tempRoutList[0]
|
||||||
|
//第一个路段加入
|
||||||
|
list.addAll(fRoute.pointList)
|
||||||
|
|
||||||
|
for (i in 1 until tempRoutList.size) {
|
||||||
|
val route = tempRoutList[i]
|
||||||
|
val list2 = ArrayList(route.pointList.toList())
|
||||||
|
list2.removeAt(0)
|
||||||
|
list.addAll(list2)
|
||||||
|
}
|
||||||
|
tempGeometry = GeometryTools.createLineString(list)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否完全偏离
|
||||||
|
*/
|
||||||
|
private fun deviationUp() {
|
||||||
|
errorCount++
|
||||||
|
if (errorCount >= DEVIATION_COUNT) {
|
||||||
|
bindingReset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定重置
|
||||||
|
*/
|
||||||
|
private fun bindingReset() {
|
||||||
|
//绑定失败次数
|
||||||
|
errorCount = 0
|
||||||
|
//当前邦定的那段route
|
||||||
|
routeIndex = -1
|
||||||
|
//当前绑定的link上哪个point
|
||||||
|
footIndex = -1
|
||||||
|
//上一次定位绑到路线的距离
|
||||||
|
lastDistance = -1
|
||||||
|
//垂足坐标
|
||||||
|
footPoint = null
|
||||||
|
//定位点集合
|
||||||
|
locationList.clear()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
BIN
app/src/main/res/drawable-xxhdpi/t0201000.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/t0201000.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
@@ -29,16 +29,29 @@
|
|||||||
android:textColor="#2F2F2F"
|
android:textColor="#2F2F2F"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sign_distance_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_alignRight="@id/sign_main_bg"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginRight="19dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="范围外"
|
||||||
|
android:textColor="#3736DB"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sign_second_icon"
|
android:id="@+id/sign_second_icon"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:gravity="center"
|
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_toRightOf="@id/sign_main_icon"
|
android:layout_toRightOf="@id/sign_main_icon"
|
||||||
|
android:gravity="center"
|
||||||
android:text=""
|
android:text=""
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/sign_bottom_text"
|
android:id="@+id/sign_bottom_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@@ -69,8 +82,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignBottom="@id/sign_main_bg"
|
android:layout_alignBottom="@id/sign_main_bg"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:padding="4dp"
|
|
||||||
android:layout_toRightOf="@id/sign_main_bg"
|
android:layout_toRightOf="@id/sign_main_bg"
|
||||||
|
android:padding="4dp"
|
||||||
android:src="@drawable/icon_sign_info"
|
android:src="@drawable/icon_sign_info"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
@@ -81,7 +94,7 @@
|
|||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_marginLeft="172dp"
|
android:layout_marginLeft="172dp"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:visibility="gone"
|
android:background="@drawable/icon_evaluation"
|
||||||
android:background="@drawable/icon_evaluation" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@@ -10,7 +10,7 @@ abstract class BaseHandler(context: AppCompatActivity, mapView: NIMapView) {
|
|||||||
protected val mMapView: NIMapView = mapView
|
protected val mMapView: NIMapView = mapView
|
||||||
|
|
||||||
fun addLayer(layer: Layer, groupType: NIMapView.LAYER_GROUPS) {
|
fun addLayer(layer: Layer, groupType: NIMapView.LAYER_GROUPS) {
|
||||||
Log.e("jingo", "增加了图层 ${layer.toString()}")
|
// Log.e("jingo", "增加了图层 ${layer.toString()}")
|
||||||
mMapView.vtmMap.layers().add(
|
mMapView.vtmMap.layers().add(
|
||||||
layer,
|
layer,
|
||||||
groupType.groupIndex
|
groupType.groupIndex
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.navinfo.collect.library.map.layers.MultiLinesLayer
|
|||||||
import com.navinfo.collect.library.map.layers.OmdbTaskLinkLayer
|
import com.navinfo.collect.library.map.layers.OmdbTaskLinkLayer
|
||||||
import com.navinfo.collect.library.utils.GeometryTools
|
import com.navinfo.collect.library.utils.GeometryTools
|
||||||
import org.oscim.android.canvas.AndroidBitmap
|
import org.oscim.android.canvas.AndroidBitmap
|
||||||
|
import org.oscim.core.GeoPoint
|
||||||
import org.oscim.layers.marker.ItemizedLayer
|
import org.oscim.layers.marker.ItemizedLayer
|
||||||
import org.oscim.layers.marker.ItemizedLayer.OnItemGestureListener
|
import org.oscim.layers.marker.ItemizedLayer.OnItemGestureListener
|
||||||
import org.oscim.layers.marker.MarkerInterface
|
import org.oscim.layers.marker.MarkerInterface
|
||||||
@@ -112,6 +113,18 @@ class LineHandler(context: AppCompatActivity, mapView: NIMapView) : BaseHandler(
|
|||||||
layer
|
layer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮一条线
|
||||||
|
*/
|
||||||
|
fun showLine(list:List<GeoPoint>) {
|
||||||
|
try {
|
||||||
|
mDefaultPathLayer.clearPath()
|
||||||
|
mDefaultPathLayer.setPoints(list)
|
||||||
|
mDefaultPathLayer.isEnabled = true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Toast.makeText(mContext, "高亮路线失败 ${e.message}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 高亮一条线
|
* 高亮一条线
|
||||||
@@ -126,6 +139,7 @@ class LineHandler(context: AppCompatActivity, mapView: NIMapView) : BaseHandler(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消高亮线
|
* 取消高亮线
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class OMDBDataDecoder extends TileDecoder {
|
|||||||
properties.putAll(renderEntity.getProperties());
|
properties.putAll(renderEntity.getProperties());
|
||||||
parseGeometry(renderEntity.getTable(), renderEntity.getWkt(), properties);
|
parseGeometry(renderEntity.getTable(), renderEntity.getWkt(), properties);
|
||||||
}else{
|
}else{
|
||||||
Log.e("qj","render"+renderEntity.name+"=="+renderEntity.getZoomMin()+"==="+renderEntity.getZoomMax()+"==="+renderEntity.getEnable());
|
// Log.e("qj","render"+renderEntity.name+"=="+renderEntity.getZoomMin()+"==="+renderEntity.getZoomMax()+"==="+renderEntity.getEnable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
package com.navinfo.collect.library.utils
|
||||||
|
|
||||||
|
import org.locationtech.jts.geom.*
|
||||||
|
import org.locationtech.jts.io.WKTWriter
|
||||||
|
import org.oscim.core.GeoPoint
|
||||||
|
|
||||||
|
class FootAndDistance(private val point: GeoPoint) {
|
||||||
|
|
||||||
|
private val pt = arrayOf(Coordinate(), Coordinate())
|
||||||
|
private var distance = Double.NaN
|
||||||
|
private var isNull = true
|
||||||
|
var footIndex = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this instance.
|
||||||
|
*/
|
||||||
|
fun initialize() {
|
||||||
|
isNull = true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the points, computing the distance between them.
|
||||||
|
* @param p0 the 1st point
|
||||||
|
* @param p1 the 2nd point
|
||||||
|
*/
|
||||||
|
fun initialize(p0: Coordinate, p1: Coordinate) {
|
||||||
|
initialize(p0, p1, p0.distance(p1))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the points, avoiding recomputing the distance.
|
||||||
|
* @param p0 the 1st point
|
||||||
|
* @param p1 the 2nd point
|
||||||
|
* @param distance the distance between p0 and p1
|
||||||
|
*/
|
||||||
|
fun initialize(p0: Coordinate, p1: Coordinate, distance: Double) {
|
||||||
|
pt[0].setCoordinate(p0)
|
||||||
|
pt[1].setCoordinate(p1)
|
||||||
|
this.distance = distance
|
||||||
|
isNull = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the distance between the paired points
|
||||||
|
* @return the distance between the paired points
|
||||||
|
*/
|
||||||
|
fun getDistance(): Double {
|
||||||
|
return distance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the paired points
|
||||||
|
* @return the paired points
|
||||||
|
*/
|
||||||
|
fun getCoordinates(): Array<Coordinate> {
|
||||||
|
return pt
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets one of the paired points
|
||||||
|
* @param i the index of the paired point (0 or 1)
|
||||||
|
* @return A point
|
||||||
|
*/
|
||||||
|
fun getCoordinate(i: Int): Coordinate {
|
||||||
|
return pt[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun setMinimum(p0: Coordinate, p1: Coordinate): Boolean {
|
||||||
|
if (isNull) {
|
||||||
|
initialize(p0, p1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val dist = p0.distance(p1)
|
||||||
|
if (dist < distance) {
|
||||||
|
initialize(p0, p1, dist)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return WKTWriter.toLineString(pt[0], pt[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getMeterDistance(): Double {
|
||||||
|
return if (!distance.isNaN() && pt.isNotEmpty())
|
||||||
|
GeometryTools.getDistance(
|
||||||
|
point.latitude,
|
||||||
|
point.longitude,
|
||||||
|
pt[0].y,
|
||||||
|
pt[0].x
|
||||||
|
)
|
||||||
|
else {
|
||||||
|
Double.NaN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeDistance(geom: Geometry, pt: Coordinate) {
|
||||||
|
when (geom) {
|
||||||
|
is LineString -> {
|
||||||
|
computeDistance(geom, pt)
|
||||||
|
}
|
||||||
|
is Polygon -> {
|
||||||
|
computeDistance(geom, pt)
|
||||||
|
}
|
||||||
|
is GeometryCollection -> {
|
||||||
|
for (i in 0 until geom.numGeometries) {
|
||||||
|
val g = geom.getGeometryN(i)
|
||||||
|
computeDistance(g, pt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> { // assume geom is Point
|
||||||
|
setMinimum(geom.coordinate, pt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeDistance(line: LineString, pt: Coordinate) {
|
||||||
|
val tempSegment = LineSegment()
|
||||||
|
val coords = line.coordinates
|
||||||
|
for (i in 0 until (coords.size - 1)) {
|
||||||
|
tempSegment.setCoordinates(coords[i], coords[i + 1])
|
||||||
|
// this is somewhat inefficient - could do better
|
||||||
|
val closestPt = tempSegment.closestPoint(pt)
|
||||||
|
if (setMinimum(closestPt, pt)) {
|
||||||
|
footIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeDistance(segment: LineSegment, pt: Coordinate) {
|
||||||
|
val closestPt = segment.closestPoint(pt)
|
||||||
|
setMinimum(closestPt, pt)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun computeDistance(poly: Polygon, pt: Coordinate) {
|
||||||
|
computeDistance(poly.exteriorRing, pt)
|
||||||
|
for (i in 0 until poly.numInteriorRing) {
|
||||||
|
computeDistance(poly.getInteriorRingN(i), pt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,9 +4,6 @@ import android.graphics.Point;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.locationtech.jts.algorithm.distance.DistanceToPoint;
|
|
||||||
import org.locationtech.jts.algorithm.distance.PointPairDistance;
|
|
||||||
import org.locationtech.jts.geom.Coordinate;
|
import org.locationtech.jts.geom.Coordinate;
|
||||||
import org.locationtech.jts.geom.Geometry;
|
import org.locationtech.jts.geom.Geometry;
|
||||||
import org.locationtech.jts.geom.GeometryFactory;
|
import org.locationtech.jts.geom.GeometryFactory;
|
||||||
@@ -428,148 +425,6 @@ public class GeometryTools {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeoPoint getLineStringCenter(String lineString) {
|
|
||||||
List<GeoPoint> points = getGeoPoints(lineString);
|
|
||||||
return getLineStringCenter(points);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoPoint getLineStringCenter(List<GeoPoint> points) {
|
|
||||||
if (points != null && points.size() > 1) {
|
|
||||||
if (points.size() == 2) {
|
|
||||||
double x1 = points.get(0).getLongitude();
|
|
||||||
double y1 = points.get(0).getLatitude();
|
|
||||||
double x2 = points.get(1).getLongitude();
|
|
||||||
double y2 = points.get(1).getLatitude();
|
|
||||||
GeoPoint newPoint = new GeoPoint((y1 + y2) / 2, (x1 + x2) / 2);
|
|
||||||
return newPoint;
|
|
||||||
} else {
|
|
||||||
double total = 0;
|
|
||||||
ArrayList<Double> dList = new ArrayList<Double>();
|
|
||||||
for (int i = 0; i < points.size() - 1; i++) {
|
|
||||||
double lt = total;
|
|
||||||
double dis = distanceToDouble(points.get(i), points.get(i + 1));
|
|
||||||
dList.add(lt + dis);
|
|
||||||
total += dis;
|
|
||||||
}
|
|
||||||
total = total / 2;
|
|
||||||
for (int i = 0; i < dList.size(); i++) {
|
|
||||||
double a = dList.get(i);
|
|
||||||
double b = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
b = dList.get(i - 1);
|
|
||||||
}
|
|
||||||
if (a > total) {
|
|
||||||
if (a - total < 4) {
|
|
||||||
return points.get(i);
|
|
||||||
}
|
|
||||||
double dx = (a - total) * 0.5 / (a - b);
|
|
||||||
GeoPoint point1 = points.get(i);
|
|
||||||
GeoPoint point2 = points.get(i + 1);
|
|
||||||
double x;
|
|
||||||
if (point1.getLongitude() < point2.getLongitude()) {
|
|
||||||
x = (point2.getLongitude() - point1.getLongitude()) * dx;
|
|
||||||
x = point2.getLongitude() - x;
|
|
||||||
} else {
|
|
||||||
x = (point1.getLongitude() - point2.getLongitude()) * dx;
|
|
||||||
x = point2.getLongitude() + x;
|
|
||||||
}
|
|
||||||
double y;
|
|
||||||
if (point1.getLatitude() > point2.getLatitude()) {
|
|
||||||
y = (point1.getLatitude() - point2.getLatitude()) * dx;
|
|
||||||
y = point2.getLatitude() + y;
|
|
||||||
} else {
|
|
||||||
y = (point2.getLatitude() - point1.getLatitude()) * dx;
|
|
||||||
y = point2.getLatitude() - y;
|
|
||||||
}
|
|
||||||
GeoPoint geoPoint = new GeoPoint(y, x);
|
|
||||||
return geoPoint;
|
|
||||||
} else {
|
|
||||||
if (total - a < 4) {
|
|
||||||
return points.get(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GeoPoint getLineStringCenter(List<GeoPoint> points, int[] index) {
|
|
||||||
if (points != null && points.size() > 1) {
|
|
||||||
if (points.size() == 2) {
|
|
||||||
double x1 = points.get(0).getLongitude();
|
|
||||||
double y1 = points.get(0).getLatitude();
|
|
||||||
double x2 = points.get(1).getLongitude();
|
|
||||||
double y2 = points.get(1).getLatitude();
|
|
||||||
GeoPoint newPoint = new GeoPoint((y1 + y2) / 2, (x1 + x2) / 2);
|
|
||||||
if (index != null && index.length > 1) {
|
|
||||||
index[0] = 0;
|
|
||||||
index[1] = 1;
|
|
||||||
}
|
|
||||||
return newPoint;
|
|
||||||
} else {
|
|
||||||
double total = 0;
|
|
||||||
ArrayList<Double> dList = new ArrayList<Double>();
|
|
||||||
for (int i = 0; i < points.size() - 1; i++) {
|
|
||||||
double lt = total;
|
|
||||||
double dis = distance(points.get(i).toString(), points.get(i + 1).toString());
|
|
||||||
dList.add(lt + dis);
|
|
||||||
total += dis;
|
|
||||||
}
|
|
||||||
total = total / 2;
|
|
||||||
for (int i = 0; i < dList.size(); i++) {
|
|
||||||
double a = dList.get(i);
|
|
||||||
double b = 0;
|
|
||||||
if (i > 0) {
|
|
||||||
b = dList.get(i - 1);
|
|
||||||
}
|
|
||||||
if (a > total) {
|
|
||||||
if (a - total < 4) {
|
|
||||||
if (index != null && index.length > 1) {
|
|
||||||
index[0] = i;
|
|
||||||
index[1] = i + 1;
|
|
||||||
}
|
|
||||||
return points.get(i);
|
|
||||||
}
|
|
||||||
double dx = (a - total) * 0.5 / (a - b);
|
|
||||||
GeoPoint point1 = points.get(i);
|
|
||||||
GeoPoint point2 = points.get(i + 1);
|
|
||||||
double x;
|
|
||||||
if (point1.getLongitude() < point2.getLongitude()) {
|
|
||||||
x = (point2.getLongitude() - point1.getLongitude()) * dx;
|
|
||||||
x = point2.getLongitude() - x;
|
|
||||||
} else {
|
|
||||||
x = (point1.getLongitude() - point2.getLongitude()) * dx;
|
|
||||||
x = point2.getLongitude() + x;
|
|
||||||
}
|
|
||||||
double y;
|
|
||||||
if (point1.getLatitude() > point2.getLatitude()) {
|
|
||||||
y = (point1.getLatitude() - point2.getLatitude()) * dx;
|
|
||||||
y = point2.getLatitude() + y;
|
|
||||||
} else {
|
|
||||||
y = (point2.getLatitude() - point1.getLatitude()) * dx;
|
|
||||||
y = point2.getLatitude() - y;
|
|
||||||
}
|
|
||||||
GeoPoint geoPoint = new GeoPoint(y, x);
|
|
||||||
if (index != null && index.length > 1) {
|
|
||||||
index[0] = i;
|
|
||||||
index[1] = i + 1;
|
|
||||||
}
|
|
||||||
return geoPoint;
|
|
||||||
} else {
|
|
||||||
if (total - a < 4) {
|
|
||||||
if (index != null && index.length > 1) {
|
|
||||||
index[0] = i;
|
|
||||||
index[1] = i + 1;
|
|
||||||
}
|
|
||||||
return points.get(i + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LINESTRING (116.4206899999999933 39.9620999999999995,
|
* LINESTRING (116.4206899999999933 39.9620999999999995,
|
||||||
@@ -1142,39 +997,6 @@ public class GeometryTools {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 点与几何最近点位置
|
|
||||||
*
|
|
||||||
* @param list
|
|
||||||
* @param geoPoint
|
|
||||||
* @return geopoint
|
|
||||||
* @author qiji
|
|
||||||
*/
|
|
||||||
public static GeoPoint getZuijinGeoPoint(List<GeoPoint> list, GeoPoint geoPoint) {//MapManager.getInstance().getMap().getMapCenterGeoLocation()屏幕中心点
|
|
||||||
|
|
||||||
if (list == null || list.size() == 0 || geoPoint == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
double dis = 0;
|
|
||||||
|
|
||||||
GeoPoint geo = null;
|
|
||||||
|
|
||||||
for (GeoPoint geopoint : list) {
|
|
||||||
|
|
||||||
double disTemp = distanceToDouble(geoPoint, geopoint);
|
|
||||||
|
|
||||||
if (dis == 0 || dis < disTemp) {
|
|
||||||
|
|
||||||
dis = disTemp;
|
|
||||||
|
|
||||||
geo = geopoint;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return geo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String GeometryFormatDouble5(String geometry) {
|
public static String GeometryFormatDouble5(String geometry) {
|
||||||
try {
|
try {
|
||||||
@@ -1315,8 +1137,6 @@ public class GeometryTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public enum SNAP_TYPE {
|
public enum SNAP_TYPE {
|
||||||
/**
|
/**
|
||||||
* 像素
|
* 像素
|
||||||
@@ -1552,7 +1372,7 @@ public class GeometryTools {
|
|||||||
*/
|
*/
|
||||||
public static double getDistance(List<GeoPoint> list) {
|
public static double getDistance(List<GeoPoint> list) {
|
||||||
if (list.size() < 2) {
|
if (list.size() < 2) {
|
||||||
return 0;
|
return -1;
|
||||||
}
|
}
|
||||||
double dis = 0;
|
double dis = 0;
|
||||||
for (int i = 0; i < list.size() - 1; i++) {
|
for (int i = 0; i < list.size() - 1; i++) {
|
||||||
@@ -1600,6 +1420,12 @@ public class GeometryTools {
|
|||||||
*/
|
*/
|
||||||
private static final double EARTH_RADIUS = 6371000.0;
|
private static final double EARTH_RADIUS = 6371000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 距离转米
|
||||||
|
* @param distance
|
||||||
|
* @param latitude
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public static double convertDistanceToDegree(double distance, double latitude) {
|
public static double convertDistanceToDegree(double distance, double latitude) {
|
||||||
double radianDistance = distance / EARTH_RADIUS;
|
double radianDistance = distance / EARTH_RADIUS;
|
||||||
double radianLatitude = Math.toRadians(latitude);
|
double radianLatitude = Math.toRadians(latitude);
|
||||||
@@ -1639,28 +1465,13 @@ public class GeometryTools {
|
|||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GeoPoint> pointToLineDistance(GeoPoint point, List<GeoPoint> pointList) {
|
|
||||||
|
|
||||||
Coordinate coordinate = geoPointToMercator(point);
|
public static FootAndDistance pointToLineDistance(GeoPoint point, Geometry geometry) {
|
||||||
Coordinate[] cs = new Coordinate[pointList.size()];
|
//定义垂线
|
||||||
|
FootAndDistance pointPairDistance = new FootAndDistance(point);
|
||||||
|
Coordinate coordinate = new Coordinate(point.getLongitude(), point.getLatitude());
|
||||||
|
pointPairDistance.computeDistance(geometry,coordinate);
|
||||||
|
|
||||||
for (int i = 0; i < pointList.size(); i++) {
|
return pointPairDistance;
|
||||||
Coordinate c = geoPointToMercator(pointList.get(i));
|
|
||||||
cs[i] = c;
|
|
||||||
}
|
|
||||||
GeometryFactory factory = new GeometryFactory();
|
|
||||||
LineString lineString = factory.createLineString(cs);
|
|
||||||
PointPairDistance pointPairDistance = new PointPairDistance();
|
|
||||||
DistanceToPoint.computeDistance(
|
|
||||||
lineString,
|
|
||||||
coordinate,
|
|
||||||
pointPairDistance
|
|
||||||
);
|
|
||||||
|
|
||||||
List newPoints = new ArrayList<GeoPoint>();
|
|
||||||
for (int i = 0; i < pointPairDistance.getCoordinates().length; i++) {
|
|
||||||
newPoints.add(mercatorToGeoPoint(pointPairDistance.getCoordinate(i)));
|
|
||||||
}
|
|
||||||
return newPoints;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user