开发路径导航功能

This commit is contained in:
squallzhjch
2023-09-15 13:31:37 +08:00
parent e5ebe64e0b
commit 95f2209cc6
14 changed files with 907 additions and 408 deletions

View 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
)

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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的snodeenode
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 = ""
//如果snodeenode是顺方向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 ->

View File

@@ -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)

View File

@@ -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

View File

@@ -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的snodeenode
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 = ""
//如果sNodeeNode是顺方向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()
}
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -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>

View File

@@ -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

View File

@@ -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(
} }
} }
/** /**
* 取消高亮线 * 取消高亮线
*/ */

View File

@@ -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());
} }
} }
}); });

View File

@@ -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)
}
}
}

View File

@@ -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;
} }
} }