diff --git a/app/src/main/assets/omdb_config.json b/app/src/main/assets/omdb_config.json index 9bcd16ce..370a37b2 100644 --- a/app/src/main/assets/omdb_config.json +++ b/app/src/main/assets/omdb_config.json @@ -34,7 +34,8 @@ "name": "道路线", "zoomMin": 15, "zoomMax": 17, - "catch":true + "catch":true, + "checkLinkId": true }, "2002": { "table": "OMDB_RD_LINK_FUNCTION_CLASS", diff --git a/app/src/main/java/com/navinfo/omqs/bean/NaviRoute.kt b/app/src/main/java/com/navinfo/omqs/bean/NaviRoute.kt new file mode 100644 index 00000000..dc1f3b72 --- /dev/null +++ b/app/src/main/java/com/navinfo/omqs/bean/NaviRoute.kt @@ -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: RenderEntity? = null, + //路段总长 + var length: Double = 0.0, + //当前link在整段路径中的起点 + var startIndexInPath: Int = -1, + //当前link在整段路径中的终点 + var endIndexIntPath: Int = -1, + var itemList: MutableList? = null +) { + var pointList: MutableList = 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 +) diff --git a/app/src/main/java/com/navinfo/omqs/bean/Route.kt b/app/src/main/java/com/navinfo/omqs/bean/Route.kt deleted file mode 100644 index e57ec794..00000000 --- a/app/src/main/java/com/navinfo/omqs/bean/Route.kt +++ /dev/null @@ -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 = mutableListOf() - get() { - return field - } - set(value) { - length = GeometryTools.getDistance(value) - field = value - } -} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/db/RealmOperateHelper.kt b/app/src/main/java/com/navinfo/omqs/db/RealmOperateHelper.kt index e4dfd1f7..2360b850 100644 --- a/app/src/main/java/com/navinfo/omqs/db/RealmOperateHelper.kt +++ b/app/src/main/java/com/navinfo/omqs/db/RealmOperateHelper.kt @@ -201,7 +201,7 @@ class RealmOperateHelper() { var link: RenderEntity? = null val realm = getSelectTaskRealmInstance() val realmR = - getSelectTaskRealmTools(RenderEntity::class.java, true).equalTo("table", "OMDB_RD_LINK_KIND") + realm.where(RenderEntity::class.java).equalTo("table", "OMDB_RD_LINK_KIND") .equalTo("properties['${LinkTable.linkPid}']", linkPid).findFirst() if (realmR != null) { link = realm.copyFromRealm(realmR) @@ -288,14 +288,14 @@ class RealmOperateHelper() { .findAll() } else { // 查询realm中对应tile号的数据 - if(Constant.CATCH_ALL){ + if (Constant.CATCH_ALL) { realmList = getSelectTaskRealmTools(RenderEntity::class.java, false) .greaterThanOrEqualTo("tileX", xStart) .lessThanOrEqualTo("tileX", xEnd) .greaterThanOrEqualTo("tileY", yStart) .lessThanOrEqualTo("tileY", yEnd) .findAll() - }else{ + } else { realmList = getSelectTaskRealmTools(RenderEntity::class.java, false) .greaterThanOrEqualTo("tileX", xStart) .lessThanOrEqualTo("tileX", xEnd) diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt index 73c73440..5fc097ed 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt @@ -27,6 +27,7 @@ import com.blankj.utilcode.util.ClipboardUtils import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.tabs.TabLayout import com.navinfo.collect.library.data.entity.RenderEntity +import com.navinfo.collect.library.data.entity.TaskBean import com.navinfo.collect.library.map.NIMapController import com.navinfo.collect.library.map.handler.MeasureLayerHandler import com.navinfo.omqs.Constant @@ -38,6 +39,7 @@ import com.navinfo.omqs.databinding.ActivityMainBinding import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager import com.navinfo.omqs.tools.LayerConfigUtils import com.navinfo.omqs.ui.activity.BaseActivity +import com.navinfo.omqs.ui.dialog.LoadingDialog import com.navinfo.omqs.ui.fragment.console.ConsoleFragment import com.navinfo.omqs.ui.fragment.itemlist.ItemListFragment import com.navinfo.omqs.ui.fragment.offlinemap.OfflineMapFragment @@ -47,6 +49,7 @@ import com.navinfo.omqs.ui.fragment.tasklist.TaskManagerFragment import com.navinfo.omqs.ui.other.BaseToast import com.navinfo.omqs.ui.widget.RecyclerViewSpacesItemDecoration import com.navinfo.omqs.util.FlowEventBus +import com.navinfo.omqs.util.NaviStatus import com.navinfo.omqs.util.SignUtil import com.navinfo.omqs.util.SpeakMode import dagger.hilt.android.AndroidEntryPoint @@ -66,6 +69,12 @@ class MainActivity : BaseActivity() { private lateinit var binding: ActivityMainBinding private val viewModel by viewModels() + private val loadingDialog by lazy { + MaterialAlertDialogBuilder( + this, + com.google.android.material.R.style.MaterialAlertDialog_Material3_Animation + ).setMessage("正在计算路线中...").setCancelable(false).show() + } /** * 左侧fragment @@ -280,11 +289,10 @@ class MainActivity : BaseActivity() { //道路绑定,名称变化 viewModel.liveDataRoadName.observe(this) { if (it != null) { - binding.mainActivityRoadName.text = it.properties["name"] binding.mainActivityRoadName.visibility = View.VISIBLE + binding.mainActivityRoadName.text = it.properties["name"] } else { - binding.mainActivityRoadName.text = " " - binding.mainActivityRoadName.visibility = View.GONE + binding.mainActivityRoadName.visibility = View.INVISIBLE } } @@ -327,7 +335,7 @@ class MainActivity : BaseActivity() { 7, RoundingMode.HALF_UP ) },${BigDecimal(it.latitude).setScale(7, RoundingMode.HALF_UP)}" - if(Constant.AUTO_LOCATION){ + if (Constant.AUTO_LOCATION) { viewModel.startAutoLocationTimer() } binding.mainActivityLocation.setImageResource(R.drawable.icon_location) @@ -336,8 +344,8 @@ class MainActivity : BaseActivity() { Log.e("qj", "异常 $e") } } - viewModel.liveDataAutoLocation.observe(this){ - if(it==true){ + viewModel.liveDataAutoLocation.observe(this) { + if (it == true) { onClickLocation() } } @@ -416,8 +424,59 @@ class MainActivity : BaseActivity() { } } + viewModel.liveDataMessage.observe(this) { + Toast.makeText(this, it, Toast.LENGTH_SHORT).show() + } + + viewModel.liveDataNaviStatus.observe(this) { + when (it) { + NaviStatus.NAVI_STATUS_PATH_ERROR_BLOCKED -> { + Toast.makeText( + this, + "路径不通,请检查", + Toast.LENGTH_SHORT + ).show() + if (loadingDialog.isShowing) + loadingDialog.dismiss() + } + NaviStatus.NAVI_STATUS_PATH_PLANNING -> { + if (!loadingDialog.isShowing) + loadingDialog.show() + } + NaviStatus.NAVI_STATUS_PATH_ERROR_NODE -> { + Toast.makeText( + this, + "查询link基本信息表失败(node表)", + Toast.LENGTH_SHORT + ).show() + loadingDialog.dismiss() + } + + NaviStatus.NAVI_STATUS_PATH_ERROR_DIRECTION -> { + Toast.makeText( + this, + "查询link基本信息表失败(方向表)", + Toast.LENGTH_SHORT + ).show() + loadingDialog.dismiss() + } + NaviStatus.NAVI_STATUS_PATH_SUCCESS -> { + loadingDialog.dismiss() + } + NaviStatus.NAVI_STATUS_DISTANCE_OFF -> { + Toast.makeText( + this, + "偏离路线", + Toast.LENGTH_SHORT + ).show() + } + NaviStatus.NAVI_STATUS_DIRECTION_OFF -> { + } + } + } + viewModel.liveDataItemList.observe(this) { - if(it.isNotEmpty()) { + if (it.isNotEmpty()) { if (leftFragment == null || leftFragment !is ItemListFragment) { leftFragment = ItemListFragment { binding.mainActivityLeftFragment.visibility = View.GONE @@ -1101,7 +1160,7 @@ class MainActivity : BaseActivity() { * 路径规划 */ fun onClickRouteFragment() { - Toast.makeText(this, "功能开发中", Toast.LENGTH_SHORT).show() + viewModel.planningPath() } /** diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt index 13ea94ea..93ca83c5 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/MainViewModel.kt @@ -57,6 +57,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext import org.locationtech.jts.geom.Geometry +import org.locationtech.jts.geom.LineString import org.oscim.core.GeoPoint import org.oscim.core.MapPosition import org.oscim.map.Map @@ -86,7 +87,7 @@ class MainViewModel @Inject constructor( private var mCameraDialog: CommonDialog? = null //路径计算 - val liveDataPlanningPathStatus = MutableLiveData() + val liveDataNaviStatus = MutableLiveData() //地图点击捕捉到的质检数据ID列表 val liveDataQsRecordIdList = MutableLiveData>() @@ -119,6 +120,12 @@ class MainViewModel @Inject constructor( */ val liveDataItemList = MutableLiveData>() + /** + * 提示信息 + */ + val liveDataMessage = MutableLiveData() + + private var traceTag: String = "TRACE_TAG" /** @@ -196,9 +203,11 @@ class MainViewModel @Inject constructor( /** * 测量类型 */ - var measuringType: MeasureLayerHandler.MEASURE_TYPE = - MeasureLayerHandler.MEASURE_TYPE.DISTANCE + var measuringType: MeasureLayerHandler.MEASURE_TYPE = MeasureLayerHandler.MEASURE_TYPE.DISTANCE + /** + * 捕捉到的上一条link + */ var linkIdCache = "" private var lastNiLocaion: NiLocation? = null @@ -223,20 +232,19 @@ class MainViewModel @Inject constructor( private var currentMapZoomLevel: Int = 0 //导航信息 - private var naviEngine: NaviEngine = NaviEngine() + private var naviEngine: NaviEngine? = null + + // 0:不导航 1:导航 2:暂停 + private var naviEngineStatus = 0 // 定义一个互斥锁 private val naviMutex = Mutex() - init { - - mapController.mMapView.vtmMap.events.bind(Map.UpdateListener { e, mapPosition -> when (e) { Map.SCALE_EVENT, Map.MOVE_EVENT, Map.ROTATE_EVENT -> liveDataCenterPoint.value = mapPosition - //Map.CLEAR_EVENT->startAutoLocationTimer() } currentMapZoomLevel = mapController.mMapView.vtmMap.mapPosition.zoomLevel @@ -253,8 +261,7 @@ class MainViewModel @Inject constructor( /** * 处理点击道路捕捉回调功能 */ - mapController.mMapView.addOnNIMapClickListener( - TAG, + mapController.mMapView.addOnNIMapClickListener(TAG, //处理地图点击操作 object : OnGeoPointClickListener { override fun onMapClick(tag: String, point: GeoPoint) { @@ -279,8 +286,7 @@ class MainViewModel @Inject constructor( */ object : OnQsRecordItemClickListener { override fun onQsRecordList(tag: String, list: MutableList) { - if (tag == TAG) - liveDataQsRecordIdList.value = list + if (tag == TAG) liveDataQsRecordIdList.value = list } }, /** @@ -288,8 +294,7 @@ class MainViewModel @Inject constructor( */ object : OnTaskLinkItemClickListener { override fun onTaskLink(tag: String, taskLinkId: String) { - if (tag == TAG) - liveDataTaskLink.value = taskLinkId + if (tag == TAG) liveDataTaskLink.value = taskLinkId } }, /** @@ -297,8 +302,7 @@ class MainViewModel @Inject constructor( */ object : ONNoteItemClickListener { override fun onNote(tag: String, noteId: String) { - if (tag == TAG) - liveDataNoteId.value = noteId + if (tag == TAG) liveDataNoteId.value = noteId } }, @@ -307,11 +311,9 @@ class MainViewModel @Inject constructor( */ object : OnNiLocationItemListener { override fun onNiLocation(tag: String, index: Int, it: NiLocation) { - if (tag == TAG) - liveDataNILocationList.value = it + if (tag == TAG) liveDataNILocationList.value = it } - } - ) + }) viewModelScope.launch(Dispatchers.IO) { getTaskBean() @@ -335,43 +337,26 @@ class MainViewModel @Inject constructor( socketServer = SocketServer(mapController, traceDataBase, sharedPreferences) // viewModelScope.launch(Dispatchers.Default) { -// naviTestFlow().collect { -// naviMutex.lock() -// if (naviEngine.geometry != null) { -// //定义垂线 -// val pointPairDistance = PointPairDistance() -// val coordinate = Coordinate(it.longitude, it.latitude) -// 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()) +// naviTestFlow().collect { point -> +// if (naviEngineStatus == 1) { +// naviEngine?.let { +// naviMutex.lock() +// it.bindingRoute(null, point) +// naviMutex.unlock() // } // } -// naviMutex.unlock() // } // } } - fun naviTestFlow(): Flow = flow { - - while (true) { - emit(mapController.mMapView.vtmMap.mapPosition.geoPoint) - delay(1000) - } - } +// fun naviTestFlow(): Flow = flow { +// +// while (true) { +// emit(mapController.mMapView.vtmMap.mapPosition.geoPoint) +// delay(1000) +// } +// } /** * 获取当前任务 @@ -382,147 +367,70 @@ class MainViewModel @Inject constructor( val res = realm.where(TaskBean::class.java).equalTo("id", id).findFirst() if (res != null) { currentTaskBean = realm.copyFromRealm(res) - //planningPath(currentTaskBean!!) } realm.close() } + /** + * 规划路径 + */ + fun planningPath() { + viewModelScope.launch(Dispatchers.Default) { + naviMutex.lock() + getTaskBean() + if (currentTaskBean != null && currentTaskBean!!.status == FileManager.Companion.FileDownloadStatus.DONE) { + naviEngine = NaviEngine(niMapController = mapController, + realmOperateHelper = realmOperateHelper, + callback = object : OnNaviEngineCallbackListener { - private fun planningPath(taskBean: TaskBean) { - if (taskBean.status == FileManager.Companion.FileDownloadStatus.DONE) { -// Toast.makeText(context, "正在计算导航路径", Toast.LENGTH_SHORT).show() - viewModelScope.launch(Dispatchers.Default) { - naviMutex.lock() - naviEngine = NaviEngine() - val pathList = mutableListOf() - val realm = realmOperateHelper.getSelectTaskRealmInstance() - for (link in taskBean.hadLinkDvoList) { - //测线不参与导航 - if (link.linkStatus == 3) { - 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_KIND.name).and() - .equalTo("properties['linkPid']", link.linkPid).findFirst() - res1?.let { + override fun planningPathStatus(status: NaviStatus) { + when (status) { + NaviStatus.NAVI_STATUS_PATH_PLANNING -> naviEngineStatus = 0 + NaviStatus.NAVI_STATUS_PATH_ERROR_NODE -> naviEngineStatus = 0 + NaviStatus.NAVI_STATUS_PATH_ERROR_DIRECTION -> naviEngineStatus = 0 + NaviStatus.NAVI_STATUS_PATH_ERROR_BLOCKED -> naviEngineStatus = 0 + NaviStatus.NAVI_STATUS_PATH_SUCCESS -> naviEngineStatus = 1 + NaviStatus.NAVI_STATUS_DISTANCE_OFF -> { + } + NaviStatus.NAVI_STATUS_DIRECTION_OFF -> {} + } + liveDataNaviStatus.postValue(status) + } - 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) - } - realm.close() - //用来存储最终的导航路径 - val newRouteList = mutableListOf() - //比对路径排序用的 - 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 + override suspend fun bindingResults( + route: NaviRoute?, + list: List + ) { + val signList = mutableListOf() + for (naviRouteItem in list) { + + val signBean = SignBean( + iconId = SignUtil.getSignIcon(naviRouteItem.data), + iconText = SignUtil.getSignIconText(naviRouteItem.data), + linkId = naviRouteItem.linkId, + distance = naviRouteItem.distance, + name = SignUtil.getSignNameText(naviRouteItem.data), + bottomRightText = SignUtil.getSignBottomRightText( + naviRouteItem.data + ), + renderEntity = naviRouteItem.data, + isMoreInfo = SignUtil.isMoreInfo(naviRouteItem.data), + index = SignUtil.getRoadInfoIndex(naviRouteItem.data) + ) + signList.add(signBean) } - } - //先找其实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 (route != null) { + liveDataRoadName.postValue(route.name) + captureTopSign(route) } + liveDataSignList.postValue(signList) } - if (tempRouteList.size == 0) { - bBreak = false - } else { - if (!bHasLast && !bHasNext) { - bBreak = false - //TODO 处理错误,路径不完整 - } - } - } - } - naviEngine.routeList = newRouteList - naviMutex.unlock() + }) + naviEngine!!.planningPath(currentTaskBean!!) + } else { + liveDataMessage.postValue("请先安装任务数据") } - } else { -// Toast.makeText(context, "数据未安装,无法计算导航路径", Toast.LENGTH_SHORT).show() + naviMutex.unlock() } } @@ -530,8 +438,11 @@ class MainViewModel @Inject constructor( override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { if (key == Constant.SELECT_TASK_ID) { viewModelScope.launch(Dispatchers.IO) { + naviMutex.lock() + naviEngineStatus = 0 getTaskBean() initQsRecordData() + naviMutex.unlock() } } } @@ -544,8 +455,7 @@ class MainViewModel @Inject constructor( var list = mutableListOf() val realm = realmOperateHelper.getRealmDefaultInstance() realm.executeTransaction { - val objects = - realmOperateHelper.getRealmTools(QsRecordBean::class.java).findAll() + val objects = realmOperateHelper.getRealmTools(QsRecordBean::class.java).findAll() list = realm.copyFromRealm(objects) } realm.close() @@ -634,8 +544,10 @@ class MainViewModel @Inject constructor( //增加间距判断 if (lastNiLocaion != null) { disance = GeometryTools.getDistance( - location.latitude, location.longitude, - lastNiLocaion!!.latitude, lastNiLocaion!!.longitude + location.latitude, + location.longitude, + lastNiLocaion!!.latitude, + lastNiLocaion!!.longitude ) } //室内整理工具时不能进行轨迹存储,判断轨迹间隔要超过2.5并小于60米 @@ -649,18 +561,30 @@ class MainViewModel @Inject constructor( } } + + /** + * 导航预警信息 + */ viewModelScope.launch(Dispatchers.Default) { //用于定位点捕捉道路 mapController.locationLayerHandler.niLocationFlow.collectLatest { location -> + if (!isSelectRoad() && !GeometryTools.isCheckError( location.longitude, location.latitude ) ) { - captureLink( - GeoPoint( - location.latitude, location.longitude + if (naviEngine != null && naviEngineStatus == 1) { + naviMutex.lock() + val point = GeoPoint(location.latitude, location.longitude) + naviEngine!!.bindingRoute(location, point) + naviMutex.unlock() + } else { + captureLink( + GeoPoint( + location.latitude, location.longitude + ) ) - ) + } } } } @@ -675,18 +599,17 @@ class MainViewModel @Inject constructor( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { val itemList = realmOperateHelper.queryElement( GeometryTools.createPoint( - point.longitude, - point.latitude + point.longitude, point.latitude ), buffer = 3.2, catchAll = false, ) //增加道路线过滤原则 val filterResult = itemList.filter { - if(isHighRoad()){ - mapController.mMapView.mapLevel>=it.zoomMin&&mapController.mMapView.mapLevel<=it.zoomMax - }else{ + if (isHighRoad()) { + mapController.mMapView.mapLevel >= it.zoomMin && mapController.mMapView.mapLevel <= it.zoomMax + } else { //关闭时过滤道路线捕捉s - mapController.mMapView.mapLevel>=it.zoomMin&&mapController.mMapView.mapLevel<=it.zoomMax&&it.code!=DataCodeEnum.OMDB_RD_LINK.code + mapController.mMapView.mapLevel >= it.zoomMin && mapController.mMapView.mapLevel <= it.zoomMax && it.code != DataCodeEnum.OMDB_RD_LINK.code } }.toList() if (filterResult.size == 1) { @@ -697,10 +620,114 @@ class MainViewModel @Inject constructor( } } + /** + * 获取道路属性 + */ + private suspend fun captureTopSign(route: NaviRoute) { + try { + captureLinkState = true + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + //看板数据 + val signList = mutableListOf() + val topSignList = mutableListOf() + mapController.lineHandler.linksLayer.clear() + if (linkIdCache != route.linkId) { + + mapController.lineHandler.showLine(route.pointList) + var elementList = realmOperateHelper.queryLinkByLinkPid(route.linkId) + for (element in elementList) { + + when (element.code) { + DataCodeEnum.OMDB_MULTI_DIGITIZED.code,//上下线分离 + DataCodeEnum.OMDB_CON_ACCESS.code,//全封闭 + -> { + val signBean = SignBean( + iconId = SignUtil.getSignIcon(element), + iconText = SignUtil.getSignIconText(element), + linkId = route.linkId, + name = SignUtil.getSignNameText(element), + bottomRightText = SignUtil.getSignBottomRightText(element), + renderEntity = element, + isMoreInfo = SignUtil.isMoreInfo(element), + index = SignUtil.getRoadInfoIndex(element) + ) + if (signBean.iconText != "") { + topSignList.add( + signBean + ) + } + } + + DataCodeEnum.OMDB_LANE_NUM.code, //车道数 + DataCodeEnum.OMDB_RD_LINK_KIND.code,//种别, + DataCodeEnum.OMDB_RD_LINK_FUNCTION_CLASS.code, // 功能等级, + DataCodeEnum.OMDB_LINK_SPEEDLIMIT.code, //线限速, + DataCodeEnum.OMDB_LINK_DIRECT.code,//道路方向, + DataCodeEnum.OMDB_RAMP.code, //匝道 + DataCodeEnum.OMDB_BRIDGE.code,//桥 + DataCodeEnum.OMDB_TUNNEL.code,//隧道 + DataCodeEnum.OMDB_ROUNDABOUT.code,//环岛 + DataCodeEnum.OMDB_LINK_ATTRIBUTE_MAIN_SIDE_ACCESS.code,//出入口 + DataCodeEnum.OMDB_LINK_ATTRIBUTE_FORNTAGE.code,//辅路 + DataCodeEnum.OMDB_LINK_ATTRIBUTE_SA.code,//SA + DataCodeEnum.OMDB_LINK_ATTRIBUTE_PA.code,//PA + DataCodeEnum.OMDB_LINK_FORM1_1.code, + DataCodeEnum.OMDB_LINK_FORM1_2.code, + DataCodeEnum.OMDB_LINK_FORM1_3.code, + DataCodeEnum.OMDB_LINK_FORM2_1.code, + DataCodeEnum.OMDB_LINK_FORM2_2.code, + DataCodeEnum.OMDB_LINK_FORM2_3.code, + DataCodeEnum.OMDB_LINK_FORM2_4.code, + DataCodeEnum.OMDB_LINK_FORM2_5.code, + DataCodeEnum.OMDB_LINK_FORM2_6.code, + DataCodeEnum.OMDB_LINK_FORM2_7.code, + DataCodeEnum.OMDB_LINK_FORM2_8.code, + DataCodeEnum.OMDB_LINK_FORM2_9.code, + DataCodeEnum.OMDB_LINK_FORM2_10.code, + DataCodeEnum.OMDB_LINK_FORM2_11.code, + DataCodeEnum.OMDB_LINK_FORM2_12.code, + DataCodeEnum.OMDB_LINK_FORM2_13.code, + DataCodeEnum.OMDB_VIADUCT.code, + -> { + val signBean = SignBean( + iconId = SignUtil.getSignIcon(element), + iconText = SignUtil.getSignIconText(element), + linkId = route.linkId, + name = SignUtil.getSignNameText(element), + bottomRightText = SignUtil.getSignBottomRightText(element), + renderEntity = element, + isMoreInfo = SignUtil.isMoreInfo(element), + index = SignUtil.getRoadInfoIndex(element), + + ) + topSignList.add( + signBean + ) + } + } + } + + liveDataTopSignList.postValue(topSignList.distinctBy { it.name } + .sortedBy { it.index }) + + val speechText = SignUtil.getRoadSpeechText(topSignList) + withContext(Dispatchers.Main) { + speakMode?.speakText(speechText) + } + linkIdCache = route.linkId ?: "" + } + } + } catch (e: Exception) { + + } + } + /** * 捕获道路和面板 */ private suspend fun captureLink(point: GeoPoint) { + if (captureLinkState) { return } @@ -715,44 +742,52 @@ class MainViewModel @Inject constructor( var hisRoadName = false if (linkList.isNotEmpty()) { + val link = linkList[0] + val linkId = link.properties[RenderEntity.Companion.LinkTable.linkPid] //看板数据 val signList = mutableListOf() val topSignList = mutableListOf() mapController.lineHandler.linksLayer.clear() - - val link = linkList[0] - - val linkId = link.properties[RenderEntity.Companion.LinkTable.linkPid] - if (linkIdCache != linkId) { - + if (bSelectRoad) + mapController.markerHandle.addMarker(point, "selectLink") mapController.lineHandler.showLine(link.geometry) + val lineString: Geometry = GeometryTools.createGeometry(link.geometry) + val footAndDistance = GeometryTools.pointToLineDistance(point, lineString) + val linePoints = GeometryTools.getGeoPoints(link.geometry) + linePoints.add( + footAndDistance.footIndex + 1, + GeoPoint( + footAndDistance.getCoordinate(0).y, + footAndDistance.getCoordinate(0).x + ) + ) + val newLineString = GeometryTools.createLineString(linePoints) linkId?.let { var elementList = realmOperateHelper.queryLinkByLinkPid(it) for (element in elementList) { - if (element.code == DataCodeEnum.OMDB_LINK_NAME.code) { hisRoadName = true liveDataRoadName.postValue(element) continue } - val distance = GeometryTools.distanceToDouble( - point, GeometryTools.createGeoPoint(element.geometry) - ) - val signBean = SignBean( iconId = SignUtil.getSignIcon(element), iconText = SignUtil.getSignIconText(element), - distance = distance.toInt(), linkId = linkId, name = SignUtil.getSignNameText(element), bottomRightText = SignUtil.getSignBottomRightText(element), renderEntity = element, isMoreInfo = SignUtil.isMoreInfo(element), - index = SignUtil.getRoadInfoIndex(element) + index = SignUtil.getRoadInfoIndex(element), + distance = SignUtil.getDistance( + footAndDistance, + newLineString, + element + ) ) - Log.e("jingo", "捕捉到的数据code ${element.code}") +// Log.e("jingo", "捕捉到的数据code ${element.code}") when (element.code) { DataCodeEnum.OMDB_MULTI_DIGITIZED.code,//上下线分离 DataCodeEnum.OMDB_CON_ACCESS.code,//全封闭 @@ -797,7 +832,6 @@ class MainViewModel @Inject constructor( -> topSignList.add( signBean ) - DataCodeEnum.OMDB_SPEEDLIMIT.code,//常规点限速 DataCodeEnum.OMDB_SPEEDLIMIT_COND.code,//条件点限速 DataCodeEnum.OMDB_SPEEDLIMIT_VAR.code,//可变点限速 @@ -806,26 +840,23 @@ class MainViewModel @Inject constructor( DataCodeEnum.OMDB_LANEINFO.code,//车信 DataCodeEnum.OMDB_WARNINGSIGN.code,//危险信息 DataCodeEnum.OMDB_TOLLGATE.code,//收费站 - -> signList.add( - signBean - ) + -> { + signList.add( + signBean + ) + } } } val realm = realmOperateHelper.getSelectTaskRealmInstance() - val entityList = - realmOperateHelper.getSelectTaskRealmTools( - RenderEntity::class.java, - true - ) - .and() - .equalTo("table", DataCodeEnum.OMDB_RESTRICTION.name) - .and() - .equalTo( - "properties['linkIn']", it - ).findAll() + val entityList = realmOperateHelper.getSelectTaskRealmTools( + RenderEntity::class.java, true + ).and().equalTo("table", DataCodeEnum.OMDB_RESTRICTION.name).and() + .equalTo( + "properties['linkIn']", it + ).findAll() if (entityList.isNotEmpty()) { val outList = entityList.distinct() for (i in outList.indices) { @@ -835,7 +866,8 @@ class MainViewModel @Inject constructor( RenderEntity::class.java, true ) - .equalTo("table", DataCodeEnum.OMDB_RD_LINK_KIND.name).and() + .equalTo("table", DataCodeEnum.OMDB_RD_LINK_KIND.name) + .and() .equalTo( "properties['${RenderEntity.Companion.LinkTable.linkPid}']", outLink @@ -847,8 +879,7 @@ class MainViewModel @Inject constructor( } } mapController.lineHandler.linksLayer.addLine( - link.geometry, - Color.BLUE + link.geometry, Color.BLUE ) realm.close() } @@ -1029,7 +1060,7 @@ class MainViewModel @Inject constructor( * */ fun refreshOMDBLayer(layerConfigList: List) { // 根据获取到的配置信息,筛选未勾选的图层名称 - if (layerConfigList != null && !layerConfigList.isEmpty()) { + if (layerConfigList != null && layerConfigList.isNotEmpty()) { val omdbVisibleList = mutableListOf() layerConfigList.forEach { omdbVisibleList.addAll(it.tableMap.filter { entry -> @@ -1057,6 +1088,12 @@ class MainViewModel @Inject constructor( linkIdCache = "" mapController.lineHandler.removeLine() liveDataSignList.value = mutableListOf() + mapController.markerHandle.removeMarker("selectLink") + if (bSelectRoad && naviEngineStatus == 1) { + naviEngineStatus = 2 + } else if (naviEngineStatus == 2) { + naviEngineStatus = 1 + } } /** @@ -1146,9 +1183,7 @@ class MainViewModel @Inject constructor( } fun sendServerCommand( - context: Context, - traceVideoBean: TraceVideoBean, - indoorToolsCommand: IndoorToolsCommand + context: Context, traceVideoBean: TraceVideoBean, indoorToolsCommand: IndoorToolsCommand ) { if (TextUtils.isEmpty(Constant.INDOOR_IP)) { @@ -1162,8 +1197,7 @@ class MainViewModel @Inject constructor( val url = "http://${Constant.INDOOR_IP}:8080/sensor/service/${traceVideoBean.command}?" when (val result = networkService.sendServerCommand( - url = url, - traceVideoBean = traceVideoBean + url = url, traceVideoBean = traceVideoBean )) { is NetResult.Success<*> -> { @@ -1176,9 +1210,7 @@ class MainViewModel @Inject constructor( withContext(Dispatchers.Main) { Toast.makeText( - context, - "命令成功。", - Toast.LENGTH_LONG + context, "命令成功。", Toast.LENGTH_LONG ).show() liveIndoorToolsResp.postValue(IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_SUCCESS) @@ -1188,8 +1220,7 @@ class MainViewModel @Inject constructor( //启动双向控制服务 if (socketServer != null && socketServer!!.isServerClose) { socketServer!!.connect( - Constant.INDOOR_IP, - this@MainViewModel + Constant.INDOOR_IP, this@MainViewModel ) } @@ -1200,8 +1231,7 @@ class MainViewModel @Inject constructor( context, "命令无效${defaultUserResponse.errmsg}", Toast.LENGTH_SHORT - ) - .show() + ).show() } liveIndoorToolsResp.postValue(IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_FAILURE) } @@ -1209,9 +1239,7 @@ class MainViewModel @Inject constructor( } catch (e: IOException) { withContext(Dispatchers.Main) { Toast.makeText( - context, - "${e.message}", - Toast.LENGTH_SHORT + context, "${e.message}", Toast.LENGTH_SHORT ).show() } } @@ -1221,11 +1249,8 @@ class MainViewModel @Inject constructor( is NetResult.Error<*> -> { withContext(Dispatchers.Main) { Toast.makeText( - context, - "${result.exception.message}", - Toast.LENGTH_SHORT - ) - .show() + context, "${result.exception.message}", Toast.LENGTH_SHORT + ).show() } liveIndoorToolsResp.postValue(IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_FAILURE) } @@ -1233,11 +1258,8 @@ class MainViewModel @Inject constructor( is NetResult.Failure<*> -> { withContext(Dispatchers.Main) { Toast.makeText( - context, - "${result.code}:${result.msg}", - Toast.LENGTH_SHORT - ) - .show() + context, "${result.code}:${result.msg}", Toast.LENGTH_SHORT + ).show() } liveIndoorToolsResp.postValue(IndoorToolsResp.QR_CODE_STATUS_UPDATE_VIDEO_INFO_FAILURE) } @@ -1260,8 +1282,7 @@ class MainViewModel @Inject constructor( if (niLocation != null) { mapController.markerHandle.addMarker( GeoPoint( - niLocation.latitude, - niLocation.longitude + niLocation.latitude, niLocation.longitude ), traceTag, "", niLocation as java.lang.Object ) } @@ -1299,9 +1320,7 @@ class MainViewModel @Inject constructor( override fun onConnect(success: Boolean) { if (!success && socketServer != null) { BaseToast.makeText( - mapController.mMapView.context, - "轨迹反向控制服务失败,请确认连接是否正常!", - Toast.LENGTH_SHORT + mapController.mMapView.context, "轨迹反向控制服务失败,请确认连接是否正常!", Toast.LENGTH_SHORT ).show() } } @@ -1330,9 +1349,7 @@ class MainViewModel @Inject constructor( Log.e("qj", "反向控制$currentIndexNiLocation") } else { BaseToast.makeText( - mapController.mMapView.context, - "没有找到对应轨迹点!", - Toast.LENGTH_SHORT + mapController.mMapView.context, "没有找到对应轨迹点!", Toast.LENGTH_SHORT ).show() } } @@ -1376,8 +1393,7 @@ class MainViewModel @Inject constructor( startTimer() } } else { - Toast.makeText(mapController.mMapView.context, "无数据了!", Toast.LENGTH_LONG) - .show() + Toast.makeText(mapController.mMapView.context, "无数据了!", Toast.LENGTH_LONG).show() cancelTrace() } } @@ -1394,13 +1410,13 @@ class MainViewModel @Inject constructor( /** * 开启自动定位 */ - fun startAutoLocationTimer(){ + fun startAutoLocationTimer() { if (autoLocationTimer != null) { cancelAutoLocation() } autoLocationTimer = fixedRateTimer("", false, disAutoLocationTime, disAutoLocationTime) { liveDataAutoLocation.postValue(true) - Log.e("qj","自动定位开始执行") + Log.e("qj", "自动定位开始执行") startAutoLocationTimer() } } @@ -1473,9 +1489,7 @@ class MainViewModel @Inject constructor( } else { withContext(Dispatchers.Main) { Toast.makeText( - mapController.mMapView.context, - "未查询到数据", - Toast.LENGTH_SHORT + mapController.mMapView.context, "未查询到数据", Toast.LENGTH_SHORT ).show() } } @@ -1498,9 +1512,7 @@ class MainViewModel @Inject constructor( } else { withContext(Dispatchers.Main) { Toast.makeText( - mapController.mMapView.context, - "未查询到数据", - Toast.LENGTH_SHORT + mapController.mMapView.context, "未查询到数据", Toast.LENGTH_SHORT ).show() } } @@ -1517,9 +1529,7 @@ class MainViewModel @Inject constructor( dialog.dismiss() } else { Toast.makeText( - mapController.mMapView.context, - "输入格式不正确", - Toast.LENGTH_SHORT + mapController.mMapView.context, "输入格式不正确", Toast.LENGTH_SHORT ).show() } } diff --git a/app/src/main/java/com/navinfo/omqs/ui/activity/map/SignAdapter.kt b/app/src/main/java/com/navinfo/omqs/ui/activity/map/SignAdapter.kt index 4a04a0b4..a12f81a1 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/activity/map/SignAdapter.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/activity/map/SignAdapter.kt @@ -79,6 +79,7 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) : val bd = holder.viewBinding if (item.iconId != 0) { + bd.signMainIconBg.visibility = View.VISIBLE if (item.renderEntity.code == DataCodeEnum.OMDB_WARNINGSIGN.code) { try { var typeCode = "${item.iconId}" @@ -110,6 +111,8 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) : } else { bd.signMainIconBg.setImageResource(item.iconId) } + }else{ + bd.signMainIconBg.visibility = View.INVISIBLE } bd.signMainIcon.text = item.iconText @@ -128,6 +131,7 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) : } else { bd.signMainInfo.visibility = View.GONE } + bd.signDistanceText.text = "${item.distance}米" bd.signSecondIcon.text = "" if (item.renderEntity.code == DataCodeEnum.OMDB_SPEEDLIMIT.code) { val minSpeed = SignUtil.getSpeedLimitMinText(item.renderEntity) @@ -143,7 +147,7 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) : val bd = holder.viewBinding bd.signMoreIconsLayout.removeAllViews() bd.signBottomText.text = item.name - bd.signBottomRightText.text = item.distance.toString() + bd.signBottomRightText.text = "${item.distance}米" val list = SignUtil.getLineInfoIcons(item.renderEntity) val lineViewS = View(context) lineViewS.layoutParams = ViewGroup.LayoutParams(24, 80) @@ -215,13 +219,13 @@ class SignAdapter(private var listener: OnSignAdapterClickListener?) : holder.tag = item.name + position } - override fun refreshData(newData: List) { - super.refreshData(newData) - for (i in newData.indices) { - if (selectMoreInfoTag == newData[i].name + i) { - return - } - } - } +// override fun refreshData(newData: List) { +// super.refreshData(newData) +//// ?这是要干嘛 for (i in newData.indices) { +//// if (selectMoreInfoTag == newData[i].name + i) { +//// return +//// } +//// } +// } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt index cc27c42b..829b2aa4 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListAdapter.kt @@ -152,6 +152,7 @@ class TaskListAdapter( if (taskBean.status == FileDownloadStatus.DONE) { binding.taskDownloadBtn.visibility = View.INVISIBLE binding.taskUploadBtn.visibility = View.VISIBLE + } else { binding.taskDownloadBtn.visibility = View.VISIBLE binding.taskUploadBtn.visibility = View.INVISIBLE diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt index a34abfca..6d70679d 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskListFragment.kt @@ -7,6 +7,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast +import androidx.fragment.app.activityViewModels import androidx.recyclerview.widget.LinearLayoutManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import com.navinfo.omqs.R @@ -14,6 +15,8 @@ import com.navinfo.omqs.databinding.FragmentTaskListBinding import com.navinfo.omqs.http.taskdownload.TaskDownloadManager import com.navinfo.omqs.http.taskupload.TaskUploadManager import com.navinfo.omqs.tools.FileManager +import com.navinfo.omqs.ui.activity.map.MainActivity +import com.navinfo.omqs.ui.activity.map.MainViewModel import com.navinfo.omqs.ui.fragment.BaseFragment import com.navinfo.omqs.ui.other.shareViewModels import com.yanzhenjie.recyclerview.SwipeMenuCreator @@ -58,9 +61,6 @@ class TaskListFragment : BaseFragment() { Toast.makeText(context, "正在校验", Toast.LENGTH_SHORT).show() viewModel.checkUploadTask(binding.root.context, taskBean) } - else -> { - - } } } } diff --git a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskViewModel.kt b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskViewModel.kt index d86ba61e..24cd2849 100644 --- a/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskViewModel.kt +++ b/app/src/main/java/com/navinfo/omqs/ui/fragment/tasklist/TaskViewModel.kt @@ -12,18 +12,15 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.navinfo.collect.library.data.dao.impl.TraceDataBase 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.OnGeoPointClickListener import com.navinfo.collect.library.utils.GeometryTools import com.navinfo.collect.library.utils.MapParamUtils import com.navinfo.omqs.Constant -import com.navinfo.omqs.bean.Route import com.navinfo.omqs.db.RealmOperateHelper import com.navinfo.omqs.http.NetResult import com.navinfo.omqs.http.NetworkService 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.util.DateTimeUtil import dagger.hilt.android.lifecycle.HiltViewModel diff --git a/app/src/main/java/com/navinfo/omqs/util/NaviEngine.kt b/app/src/main/java/com/navinfo/omqs/util/NaviEngine.kt index 863ed36c..e3e10f4f 100644 --- a/app/src/main/java/com/navinfo/omqs/util/NaviEngine.kt +++ b/app/src/main/java/com/navinfo/omqs/util/NaviEngine.kt @@ -1,25 +1,623 @@ 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.omqs.bean.Route +import com.navinfo.omqs.bean.NaviRoute +import com.navinfo.omqs.bean.NaviRouteItem +import com.navinfo.omqs.db.RealmOperateHelper +import io.realm.Realm import org.locationtech.jts.geom.LineString +import org.locationtech.jts.geom.Point import org.oscim.core.GeoPoint -class NaviEngine { +public interface OnNaviEngineCallbackListener { + fun planningPathStatus(code: NaviStatus) + + // fun planningPathError(errorCode: NaviStatus, errorMessage: String) + suspend fun bindingResults(route: NaviRoute?, list: List) +} + +enum class NaviStatus { + NAVI_STATUS_PATH_PLANNING, //路径规划中 + NAVI_STATUS_PATH_ERROR_NODE,//node点缺失 + NAVI_STATUS_PATH_ERROR_DIRECTION,//缺少方向 + NAVI_STATUS_PATH_ERROR_BLOCKED,//路径不通 + NAVI_STATUS_PATH_SUCCESS,//路径规划成功 + NAVI_STATUS_DISTANCE_OFF,//距离偏离 + NAVI_STATUS_DIRECTION_OFF,//方向偏离 +} + + +class NaviEngine( + private val niMapController: NIMapController, + private val realmOperateHelper: RealmOperateHelper, + val callback: OnNaviEngineCallbackListener +) { + + /** + * 要查询的要素列表 + */ + private val QUERY_KEY_ITEM_LIST = arrayOf( + DataCodeEnum.OMDB_ELECTRONICEYE.name, + 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 + ) + + /** + * 要查询的link基本信息列表 + */ + private val QUERY_KEY_LINK_INFO_LIST = arrayOf( + DataCodeEnum.OMDB_RD_LINK.name, + DataCodeEnum.OMDB_LINK_DIRECT.name, + DataCodeEnum.OMDB_LINK_NAME.name, + ) + + /** + * 偏离距离 单位:米 + */ + private val DEVIATION_DISTANCE = 15 + + /** + * 偏离次数上限 + */ + private val DEVIATION_COUNT = 5 + + /** + * 局部匹配时,走过的路段还记录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 routeList = mutableListOf() + + /** + * 临时路径 + */ + var tempGeometry: LineString? = null + + /** + * 定位点集合 + */ + private var locationList: MutableList = mutableListOf() + + /** + * 局部匹配时的路段 + */ + var tempRoutList = mutableListOf() + + + /** + * 所有路段集合 + */ + var routeList = mutableListOf() get() { return field } set(value) { val list = mutableListOf() - 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) { - 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) list.addAll(list2) } geometry = GeometryTools.createLineString(list) field = value } + + /** + * 计算路径 + */ + suspend fun planningPath(taskBean: TaskBean) { + callback.planningPathStatus(NaviStatus.NAVI_STATUS_PATH_PLANNING) + val pathList = mutableListOf() + val realm = realmOperateHelper.getSelectTaskRealmInstance() + for (link in taskBean.hadLinkDvoList) { + //测线不参与导航 + if (link.linkStatus == 3) { + continue + } + val route = NaviRoute( + linkId = link.linkPid, + ) + + route.pointList = GeometryTools.getGeoPoints(link.geometry) + + val res = realm.where(RenderEntity::class.java).`in`("table", QUERY_KEY_LINK_INFO_LIST) + .equalTo("properties['linkPid']", link.linkPid).findAll() + var bHasNode = false + var bHasDir = false + var bHasName = false + if (res != null) { + for (entity in res) { + when (entity.code) { + DataCodeEnum.OMDB_RD_LINK.code -> { + bHasNode = true + val snodePid = entity.properties["snodePid"] + if (snodePid != null) { + route.sNode = snodePid + } else { + bHasNode = false + } + val enodePid = entity.properties["enodePid"] + if (enodePid != null) { + route.eNode = enodePid + } else { + bHasNode = false + } + } + DataCodeEnum.OMDB_LINK_DIRECT.code -> { + val direct = entity.properties["direct"] + if (direct != null) { + bHasDir = true + route.direct = direct.toInt() + } + } + DataCodeEnum.OMDB_LINK_NAME.code -> { + bHasName = true + route.name = realm.copyFromRealm(entity) + } + } + } + } + if (!bHasNode) { + callback.planningPathStatus( + NaviStatus.NAVI_STATUS_PATH_ERROR_NODE + ) + return + } + if (!bHasDir) { + callback.planningPathStatus( + NaviStatus.NAVI_STATUS_PATH_ERROR_DIRECTION + ) + return + } + pathList.add(route) + } + //用来存储最终的导航路径 + val newRouteList = mutableListOf() + //比对路径排序用的 + 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.planningPathStatus( + NaviStatus.NAVI_STATUS_PATH_ERROR_BLOCKED + ) + realm.close() + return + } + } + } + } + val itemMap: MutableMap> = mutableMapOf() + //查询每根link上的关联要素 + for (route in newRouteList) { + itemMap.clear() + //常规点限速 + val res = realm.where(RenderEntity::class.java) + .equalTo("properties['linkPid']", route.linkId).and().`in`( + "table", + QUERY_KEY_ITEM_LIST + ).findAll() + if (res.isNotEmpty()) { +// Log.e("jingo", "道路查询预警要素 ${route.linkId} ${res.size}条数据") + for (r in res) { +// Log.e("jingo", "道路查询预警要素 ${r.name}") + 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) + } + itemMap.remove(point) + } + } + route.itemList!!.sortBy { it.index } + } + } + realm.close() + routeList = newRouteList + callback.planningPathStatus(NaviStatus.NAVI_STATUS_PATH_SUCCESS) + + } + + /** + * 将要素绑定到路径上 + */ + private fun insertItemToRoute( + realm: Realm, + route: NaviRoute, + res: RenderEntity?, + itemMap: MutableMap> + ) { + 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 + ) + //测试marker +// 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)) + } + } + } + } + + /** + * 绑定道路 + */ + suspend 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() + } + 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 +// ) + matchingItem() + if (lastRouteIndex != routeIndex) { + createTempPath() + } + errorCount = 0 + break + } + } + } else { + deviationUp() + } + } + } + } + + /** + * 匹配要素 + * @point:定位点 + */ + private suspend fun matchingItem() { + + if (routeIndex > -1 && tempRoutList.isNotEmpty() && tempGeometry != null) { + Log.e("jingo", "当前${routeIndex} ${tempRoutList[0].startIndexInPath} $footIndex") + //道路前方一定距离范围内的要素信息 + val bindingItemList = mutableListOf() + //定位点到要素的路径距离 + var distance = 0.0 + //计算要素路径距离的点集合 + val disPoints = mutableListOf(footPoint!!) + //下一个要素的起点游标 + var tempIndex = footIndex - tempRoutList[0].startIndexInPath + 1 + var currentRoute: NaviRoute? = null + for (route in tempRoutList) { +// if (route.itemList != null) { +// Log.e("jingo", "${route.linkId}我有${route.itemList!!.size}个要素 ") +// } + if (route.indexInPath < routeIndex) + continue + if (route.indexInPath == routeIndex) { + currentRoute = route + } + if (route.itemList != null && route.itemList!!.isNotEmpty()) { + for (naviItem in route.itemList!!) { +// Log.e( +// "jingo", +// "我是:${naviItem.data.name} 我的点位 ${naviItem.index} 垂足点位 $footIndex" +// ) + if (naviItem.index > footIndex) { + 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 + 1 + distance = GeometryTools.getDistance(disPoints) +// Log.e("jingo", "我的距离${distance} 下一个${tempIndex} 位置${rightI}") + if (distance < FARTHEST_DISPLAY_DISTANCE && distance > -1) { + naviItem.distance = distance.toInt() + bindingItemList.add(naviItem) + } else { + break + } + } + } + if (distance >= FARTHEST_DISPLAY_DISTANCE) { + break + } + } + } + callback.bindingResults(currentRoute, 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() + 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) { + callback.planningPathStatus(NaviStatus.NAVI_STATUS_DISTANCE_OFF) + bindingReset() + } + } + + /** + * 绑定重置 + */ + private fun bindingReset() { + //绑定失败次数 + errorCount = 0 + //当前邦定的那段route + routeIndex = -1 + //当前绑定的link上哪个point + footIndex = -1 + //上一次定位绑到路线的距离 + lastDistance = -1 + //垂足坐标 + footPoint = null + //定位点集合 + locationList.clear() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt b/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt index 47bf4c38..12cc49f5 100644 --- a/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt +++ b/app/src/main/java/com/navinfo/omqs/util/SignUtil.kt @@ -1,9 +1,10 @@ package com.navinfo.omqs.util -import android.provider.ContactsContract.Data import android.util.Log import com.navinfo.collect.library.data.entity.RenderEntity import com.navinfo.collect.library.enums.DataCodeEnum +import com.navinfo.collect.library.utils.FootAndDistance +import com.navinfo.collect.library.utils.GeometryTools import com.navinfo.omqs.R import com.navinfo.omqs.bean.RoadNameBean import com.navinfo.omqs.bean.SignBean @@ -13,6 +14,10 @@ import com.navinfo.omqs.ui.fragment.signMoreInfo.TwoItemAdapter import com.navinfo.omqs.ui.fragment.signMoreInfo.TwoItemAdapterItem import org.json.JSONArray import org.json.JSONObject +import org.locationtech.jts.geom.Geometry +import org.locationtech.jts.geom.LineString +import org.locationtech.jts.geom.Point +import org.oscim.core.GeoPoint import java.lang.reflect.Field class SignUtil { @@ -808,32 +813,32 @@ class SignUtil { DataCodeEnum.OMDB_TRAFFIC_SIGN.code -> { var color = data.properties["color"] if (color != null) { - when(color){ - "0"->{ - return "颜色:未验证" + when (color) { + "0" -> { + return "颜色:未验证" } - "1"->{ + "1" -> { return "颜色:白色" } - "2"->{ + "2" -> { return "颜色:黄色" } - "3"->{ + "3" -> { return "颜色:红色" } - "5"->{ + "5" -> { return "颜色:棕色" } - "6"->{ + "6" -> { return "颜色:蓝色" } - "7"->{ + "7" -> { return "颜色:绿色" } - "8"->{ + "8" -> { return "颜色:黑色" } - "9"->{ + "9" -> { return "颜色:其他" } } @@ -1065,7 +1070,8 @@ class SignUtil { DataCodeEnum.OMDB_TRAFFIC_SIGN.code -> { var trafsignShape = data.properties["trafsignShape"] if (trafsignShape != null) { - trafsignShape = "icon_${DataCodeEnum.OMDB_TRAFFIC_SIGN.code}_${trafsignShape.lowercase()}" + trafsignShape = + "icon_${DataCodeEnum.OMDB_TRAFFIC_SIGN.code}_${trafsignShape.lowercase()}" return getResId(trafsignShape, R.drawable::class.java) } return 0 @@ -1596,6 +1602,53 @@ class SignUtil { return list } + /** + * 计算捕捉点到 + */ + fun getDistance( + footAndDistance: FootAndDistance, + lineString: Geometry, + element: RenderEntity + ): Int { + + val itemGeometry = GeometryTools.createGeometry(element.geometry) + if (itemGeometry is Point) { + val itemFoot = GeometryTools.pointToLineDistance( + GeoPoint(itemGeometry.y, itemGeometry.x), + lineString + ) + var dis = GeometryTools.getDistance( + footAndDistance.getCoordinate(0).getY(), + footAndDistance.getCoordinate(0).getX(), + itemFoot.getCoordinate(0).getY(), + itemFoot.getCoordinate(0).getX(), + ) + return if (footAndDistance.footIndex < itemFoot.footIndex) { + dis.toInt() + } else { + -dis.toInt() + } + } else if (itemGeometry is LineString) { + val itemFoot = GeometryTools.pointToLineDistance( + GeoPoint( + lineString.coordinates[0].y, + lineString.coordinates[0].x + ), lineString + ) + var dis = GeometryTools.getDistance( + footAndDistance.getCoordinate(0).getY(), + footAndDistance.getCoordinate(0).getX(), + itemFoot.getCoordinate(0).getY(), + itemFoot.getCoordinate(0).getX(), + ) + return if (footAndDistance.footIndex < itemFoot.footIndex) { + dis.toInt() + } else { + -dis.toInt() + } + } + return 0 + } } diff --git a/app/src/main/res/drawable-xxhdpi/t0201000.png b/app/src/main/res/drawable-xxhdpi/t0201000.png new file mode 100644 index 00000000..6f438e81 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/t0201000.png differ diff --git a/app/src/main/res/layout/adapter_sign.xml b/app/src/main/res/layout/adapter_sign.xml index 668abcff..6f49279f 100644 --- a/app/src/main/res/layout/adapter_sign.xml +++ b/app/src/main/res/layout/adapter_sign.xml @@ -29,16 +29,29 @@ android:textColor="#2F2F2F" android:textSize="16sp" /> + + + @@ -81,7 +94,7 @@ android:layout_alignParentTop="true" android:layout_marginLeft="172dp" android:layout_marginTop="4dp" - android:visibility="gone" - android:background="@drawable/icon_evaluation" /> + android:background="@drawable/icon_evaluation" + android:visibility="gone" /> \ No newline at end of file diff --git a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/BaseHandler.kt b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/BaseHandler.kt index 1efce364..6d7317bd 100644 --- a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/BaseHandler.kt +++ b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/BaseHandler.kt @@ -10,7 +10,7 @@ abstract class BaseHandler(context: AppCompatActivity, mapView: NIMapView) { protected val mMapView: NIMapView = mapView fun addLayer(layer: Layer, groupType: NIMapView.LAYER_GROUPS) { - Log.e("jingo", "增加了图层 ${layer.toString()}") +// Log.e("jingo", "增加了图层 ${layer.toString()}") mMapView.vtmMap.layers().add( layer, groupType.groupIndex diff --git a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LineHandler.kt b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LineHandler.kt index d4b830b8..139b2816 100644 --- a/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LineHandler.kt +++ b/collect-library/src/main/java/com/navinfo/collect/library/map/handler/LineHandler.kt @@ -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.utils.GeometryTools import org.oscim.android.canvas.AndroidBitmap +import org.oscim.core.GeoPoint import org.oscim.layers.marker.ItemizedLayer import org.oscim.layers.marker.ItemizedLayer.OnItemGestureListener import org.oscim.layers.marker.MarkerInterface @@ -112,6 +113,18 @@ class LineHandler(context: AppCompatActivity, mapView: NIMapView) : BaseHandler( layer } + /** + * 高亮一条线 + */ + fun showLine(list:List) { + 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( } } + /** * 取消高亮线 */ diff --git a/collect-library/src/main/java/com/navinfo/collect/library/map/source/OMDBDataDecoder.java b/collect-library/src/main/java/com/navinfo/collect/library/map/source/OMDBDataDecoder.java index a84895ab..fdb2b98a 100644 --- a/collect-library/src/main/java/com/navinfo/collect/library/map/source/OMDBDataDecoder.java +++ b/collect-library/src/main/java/com/navinfo/collect/library/map/source/OMDBDataDecoder.java @@ -77,7 +77,7 @@ public class OMDBDataDecoder extends TileDecoder { properties.putAll(renderEntity.getProperties()); parseGeometry(renderEntity.getTable(), renderEntity.getWkt(), properties); }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()); } } }); diff --git a/collect-library/src/main/java/com/navinfo/collect/library/utils/FootAndDistance.kt b/collect-library/src/main/java/com/navinfo/collect/library/utils/FootAndDistance.kt new file mode 100644 index 00000000..3a3d3e23 --- /dev/null +++ b/collect-library/src/main/java/com/navinfo/collect/library/utils/FootAndDistance.kt @@ -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 { + 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) + } + } + +} \ No newline at end of file diff --git a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java index 05011a0d..003e494a 100644 --- a/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java +++ b/collect-library/src/main/java/com/navinfo/collect/library/utils/GeometryTools.java @@ -4,9 +4,6 @@ import android.graphics.Point; import android.os.Build; 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.Geometry; import org.locationtech.jts.geom.GeometryFactory; @@ -446,148 +443,15 @@ public class GeometryTools { } - public static GeoPoint getLineStringCenter(String lineString) { - List points = getGeoPoints(lineString); - return getLineStringCenter(points); + public static double distanceToDouble(Geometry startGeoPoint, Geometry endGeoPoint) { + if (startGeoPoint != null && endGeoPoint != null) { + double d = startGeoPoint.distance(endGeoPoint); + return convertDistanceToDegree(d, startGeoPoint.getCoordinate().y); + } + return 0; + } - public static GeoPoint getLineStringCenter(List 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 dList = new ArrayList(); - 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 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 dList = new ArrayList(); - 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, @@ -1160,39 +1024,6 @@ public class GeometryTools { return null; } - /** - * 点与几何最近点位置 - * - * @param list - * @param geoPoint - * @return geopoint - * @author qiji - */ - public static GeoPoint getZuijinGeoPoint(List 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) { try { @@ -1333,8 +1164,6 @@ public class GeometryTools { } - - public enum SNAP_TYPE { /** * 像素 @@ -1570,7 +1399,7 @@ public class GeometryTools { */ public static double getDistance(List list) { if (list.size() < 2) { - return 0; + return -1; } double dis = 0; for (int i = 0; i < list.size() - 1; i++) { @@ -1618,6 +1447,12 @@ public class GeometryTools { */ private static final double EARTH_RADIUS = 6371000.0; + /** + * 距离转米 + * @param distance + * @param latitude + * @return + */ public static double convertDistanceToDegree(double distance, double latitude) { double radianDistance = distance / EARTH_RADIUS; double radianLatitude = Math.toRadians(latitude); @@ -1669,28 +1504,13 @@ public class GeometryTools { return point; } - public static List pointToLineDistance(GeoPoint point, List pointList) { - Coordinate coordinate = geoPointToMercator(point); - Coordinate[] cs = new Coordinate[pointList.size()]; + public static FootAndDistance pointToLineDistance(GeoPoint point, Geometry geometry) { + //定义垂线 + 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++) { - 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(); - for (int i = 0; i < pointPairDistance.getCoordinates().length; i++) { - newPoints.add(mercatorToGeoPoint(pointPairDistance.getCoordinate(i))); - } - return newPoints; + return pointPairDistance; } }