Merge branch 'master' of gitlab.navinfo.com:CollectVehicle/OneMapQS
Conflicts: app/src/main/java/com/navinfo/omqs/OMQSApplication.kt app/src/main/java/com/navinfo/omqs/ui/activity/map/MainActivity.kt collect-library/src/main/java/com/navinfo/collect/library/map/handler/LayerManagerHandler.kt
This commit is contained in:
@@ -12,9 +12,7 @@ import dagger.hilt.android.HiltAndroidApp
|
||||
import org.videolan.vlc.Util
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.math.BigInteger
|
||||
import java.security.MessageDigest
|
||||
|
||||
@HiltAndroidApp
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.locationtech.spatial4j.distance.DistanceUtils
|
||||
import org.oscim.core.GeoPoint
|
||||
import org.oscim.core.MercatorProjection
|
||||
import javax.inject.Inject
|
||||
import kotlin.streams.toList
|
||||
|
||||
|
||||
class RealmOperateHelper() {
|
||||
@@ -25,29 +26,126 @@ class RealmOperateHelper() {
|
||||
* @param point 点位经纬度信息
|
||||
* @param buffer 点位的外扩距离
|
||||
* @param bufferType 点位外扩距离的单位: 米-Meter,像素-PIXEL
|
||||
* @param order 是否需要排序
|
||||
* @param sort 是否需要排序
|
||||
* */
|
||||
suspend fun queryLink(point: Point, buffer: Double = DEFAULT_BUFFER, bufferType: BUFFER_TYPE = DEFAULT_BUFFER_TYPE, order: Boolean = false): MutableList<RenderEntity> {
|
||||
suspend fun queryLink(point: Point, buffer: Double = DEFAULT_BUFFER, bufferType: BUFFER_TYPE = DEFAULT_BUFFER_TYPE, sort: Boolean = false): MutableList<RenderEntity> {
|
||||
val result = mutableListOf<RenderEntity>()
|
||||
withContext(Dispatchers.IO) {
|
||||
val polygon = getPolygonFromPoint(point, buffer, bufferType)
|
||||
// 根据polygon查询相交的tile号
|
||||
val tileXSet = mutableSetOf<Int>()
|
||||
tileXSet.toString()
|
||||
GeometryToolsKt.getTileXByGeometry(polygon.toString(), tileXSet)
|
||||
val tileYSet = mutableSetOf<Int>()
|
||||
GeometryToolsKt.getTileYByGeometry(polygon.toString(), tileYSet)
|
||||
|
||||
// 对tileXSet和tileYSet查询最大最小值
|
||||
val xStart = tileXSet.stream().min(Comparator.naturalOrder()).orElse(null)
|
||||
val xEnd = tileXSet.stream().max(Comparator.naturalOrder()).orElse(null)
|
||||
val yStart = tileYSet.stream().min(Comparator.naturalOrder()).orElse(null)
|
||||
val yEnd = tileYSet.stream().max(Comparator.naturalOrder()).orElse(null)
|
||||
// 查询realm中对应tile号的数据
|
||||
Realm.getDefaultInstance().where(RenderEntity::class.java).equalTo("table", "HAD_LINK")
|
||||
val realmList = Realm.getDefaultInstance().where(RenderEntity::class.java)
|
||||
.equalTo("table", "HAD_LINK")
|
||||
.and()
|
||||
.rawPredicate("tileX>=$xStart and tileX<=$xEnd and tileY>=$yStart and tileY<=$yEnd")
|
||||
.findAll()
|
||||
// 将获取到的数据和查询的polygon做相交,只返回相交的数据
|
||||
val queryResult = realmList?.stream()?.filter {
|
||||
polygon.intersects(it.wkt)
|
||||
}?.toList()
|
||||
queryResult?.let {
|
||||
result.addAll(queryResult)
|
||||
}
|
||||
if (sort) {
|
||||
result.clear()
|
||||
result.addAll(sortRenderEntity(point, result))
|
||||
}
|
||||
}
|
||||
return mutableListOf()
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 根据当前点位查询匹配的除Link外的其他要素数据
|
||||
* @param point 点位经纬度信息
|
||||
* @param buffer 点位的外扩距离
|
||||
* @param bufferType 点位外扩距离的单位: 米-Meter,像素-PIXEL
|
||||
* @param sort 是否需要排序
|
||||
* */
|
||||
suspend fun queryElement(point: Point, buffer: Double = DEFAULT_BUFFER, bufferType: BUFFER_TYPE = DEFAULT_BUFFER_TYPE, sort: Boolean = false): MutableList<RenderEntity> {
|
||||
val result = mutableListOf<RenderEntity>()
|
||||
withContext(Dispatchers.IO) {
|
||||
val polygon = getPolygonFromPoint(point, buffer, bufferType)
|
||||
// 根据polygon查询相交的tile号
|
||||
val tileXSet = mutableSetOf<Int>()
|
||||
tileXSet.toString()
|
||||
GeometryToolsKt.getTileXByGeometry(polygon.toString(), tileXSet)
|
||||
val tileYSet = mutableSetOf<Int>()
|
||||
GeometryToolsKt.getTileYByGeometry(polygon.toString(), tileYSet)
|
||||
|
||||
// 对tileXSet和tileYSet查询最大最小值
|
||||
val xStart = tileXSet.stream().min(Comparator.naturalOrder()).orElse(null)
|
||||
val xEnd = tileXSet.stream().max(Comparator.naturalOrder()).orElse(null)
|
||||
val yStart = tileYSet.stream().min(Comparator.naturalOrder()).orElse(null)
|
||||
val yEnd = tileYSet.stream().max(Comparator.naturalOrder()).orElse(null)
|
||||
// 查询realm中对应tile号的数据
|
||||
val realmList = Realm.getDefaultInstance().where(RenderEntity::class.java)
|
||||
.notEqualTo("table", "HAD_LINK")
|
||||
.and()
|
||||
.rawPredicate("tileX>=$xStart and tileX<=$xEnd and tileY>=$yStart and tileY<=$yEnd")
|
||||
.findAll()
|
||||
// 将获取到的数据和查询的polygon做相交,只返回相交的数据
|
||||
val queryResult = realmList?.stream()?.filter {
|
||||
polygon.intersects(it.wkt)
|
||||
}?.toList()
|
||||
queryResult?.let {
|
||||
result.addAll(queryResult)
|
||||
}
|
||||
if (sort) {
|
||||
result.clear()
|
||||
result.addAll(sortRenderEntity(point, result))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据linkPid查询关联的要素(除去Link数据)
|
||||
* @param point 点位经纬度信息
|
||||
* @param buffer 点位的外扩距离
|
||||
* @param bufferType 点位外扩距离的单位: 米-Meter,像素-PIXEL
|
||||
* @param sort 是否需要排序
|
||||
* */
|
||||
suspend fun queryLinkByLinkPid(linkPid: String): MutableList<RenderEntity> {
|
||||
val result = mutableListOf<RenderEntity>()
|
||||
withContext(Dispatchers.IO) {
|
||||
val realmList = Realm.getDefaultInstance().where(RenderEntity::class.java)
|
||||
.notEqualTo("table", "HAD_LINK")
|
||||
.and()
|
||||
.equalTo("properties['LINK_PID']", linkPid)
|
||||
.findAll()
|
||||
result.addAll(realmList)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的点位对数据排序
|
||||
* @param point 点位经纬度信息
|
||||
* @param unSortList 未排序的数据
|
||||
* @return 排序后的数据
|
||||
* */
|
||||
fun sortRenderEntity(point: Point, unSortList: MutableList<RenderEntity>): List<RenderEntity> {
|
||||
val sortList = unSortList.stream().sorted { renderEntity, renderEntity2 ->
|
||||
val near = point.distance(renderEntity.wkt) - point.distance(renderEntity2.wkt)
|
||||
if (near<0) -1 else 1
|
||||
}.toList()
|
||||
return sortList
|
||||
}
|
||||
|
||||
private fun getPolygonFromPoint(point: Point, buffer: Double = DEFAULT_BUFFER, bufferType: BUFFER_TYPE = DEFAULT_BUFFER_TYPE): Polygon {
|
||||
// 首先计算当前点位的buffer组成的geometry
|
||||
val wkt: Polygon = if (bufferType == BUFFER_TYPE.METER) { // 如果单位是米
|
||||
// 计算米和地球角度之间的关系,在Spatial4J中,经度和纬度的单位是度,而不是米。因此,将距离从米转换为度需要使用一个转换因子,这个转换因子是由地球的周长和360度之间的比例计算得出的。
|
||||
// 在这个例子中,使用的转换因子是111000.0,这是因为地球的周长约为40075公里,而每个经度的距离大约是地球周长的1/360,因此每个经度的距离约为111.32公里
|
||||
val distanceDegrees = DistanceUtils.dist2Degrees(buffer, DistanceUtils.EARTH_MEAN_RADIUS_KM) * 111000.0
|
||||
val distanceDegrees = GeometryTools.convertDistanceToDegree(buffer, point.y)
|
||||
// 计算外扩矩形
|
||||
BufferOp.bufferOp(point, distanceDegrees) as Polygon
|
||||
} else { // 如果单位是像素,需要根据当前屏幕像素计算出经纬度变化
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
package com.navinfo.omqs.db;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.room.Database;
|
||||
import androidx.room.Room;
|
||||
import androidx.room.RoomDatabase;
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||
import com.navinfo.collect.library.data.dao.impl.INiLocationDao;
|
||||
import com.navinfo.collect.library.data.entity.NiLocation;
|
||||
import com.tencent.wcdb.database.SQLiteCipherSpec;
|
||||
import com.tencent.wcdb.database.SQLiteDatabase;
|
||||
import com.tencent.wcdb.repair.BackupKit;
|
||||
import com.tencent.wcdb.repair.RecoverKit;
|
||||
import com.tencent.wcdb.room.db.WCDBDatabase;
|
||||
import com.tencent.wcdb.room.db.WCDBOpenHelperFactory;
|
||||
|
||||
@Database(entities = { NiLocation.class},version = 1, exportSchema = false)
|
||||
public abstract class TraceDataBase extends RoomDatabase {
|
||||
// marking the instance as volatile to ensure atomic access to the variable
|
||||
/**
|
||||
* 数据库单例对象
|
||||
*/
|
||||
private static volatile TraceDataBase INSTANCE;
|
||||
|
||||
/**
|
||||
* 地图坐标库类
|
||||
*/
|
||||
public abstract INiLocationDao getNiLocationDao();
|
||||
|
||||
/**
|
||||
* 数据库秘钥
|
||||
*/
|
||||
private final static String DB_PASSWORD = "123456";
|
||||
|
||||
public static TraceDataBase getDatabase(final Context context, final String name) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (TraceDataBase.class) {
|
||||
if (INSTANCE == null) {
|
||||
// [WCDB] To use Room library with WCDB, pass a WCDBOpenHelper factory object
|
||||
// to the database builder with .openHelperFactory(...). In the factory object,
|
||||
// you can specify passphrase and cipher options to open or create encrypted
|
||||
// database, as well as optimization options like asynchronous checkpoint.
|
||||
SQLiteCipherSpec cipherSpec = new SQLiteCipherSpec()
|
||||
.setPageSize(1024)
|
||||
.setSQLCipherVersion(3);
|
||||
WCDBOpenHelperFactory factory = new WCDBOpenHelperFactory()
|
||||
.passphrase(DB_PASSWORD.getBytes()) // passphrase to the database, remove this line for plain-text
|
||||
.cipherSpec(cipherSpec) // cipher to use, remove for default settings
|
||||
.writeAheadLoggingEnabled(true) // enable WAL mode, remove if not needed
|
||||
.asyncCheckpointEnabled(true); // enable asynchronous checkpoint, remove if not needed
|
||||
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
|
||||
TraceDataBase.class, name)
|
||||
|
||||
// [WCDB] Specify open helper to use WCDB database implementation instead
|
||||
// of the Android framework.
|
||||
.openHelperFactory(factory)
|
||||
|
||||
// Wipes and rebuilds instead of migrating if no Migration object.
|
||||
// Migration is not part of this codelab.
|
||||
.fallbackToDestructiveMigration()
|
||||
.addCallback(sRoomDatabaseCallback)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the onOpen method to populate the database.
|
||||
* For this sample, we clear the database every time it is created or opened.
|
||||
* <p>
|
||||
* If you want to populate the database only when the database is created for the 1st time,
|
||||
* override RoomDatabase.Callback()#onCreate
|
||||
*/
|
||||
private static Callback sRoomDatabaseCallback = new Callback() {
|
||||
|
||||
@Override
|
||||
public void onOpen(@NonNull SupportSQLiteDatabase db) {
|
||||
super.onOpen(db);
|
||||
// If you want to keep the data through app restarts,
|
||||
// comment out the following line.
|
||||
new PopulateDbAsync(INSTANCE).execute();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Populate the database in the background.
|
||||
* If you want to start with more words, just add them.
|
||||
*/
|
||||
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
PopulateDbAsync(TraceDataBase db) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(final Void... params) {
|
||||
// Start the app with a clean database every time.
|
||||
// Not needed if you only populate on creation.
|
||||
//mDao.deleteAll();
|
||||
Log.e("qj", "doInBackground");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据恢复
|
||||
*/
|
||||
protected boolean recoverData(){
|
||||
if(INSTANCE!=null){
|
||||
SQLiteDatabase sqlite = ((WCDBDatabase) INSTANCE.getOpenHelper().getWritableDatabase()).getInnerDatabase();
|
||||
RecoverKit recover = new RecoverKit(
|
||||
sqlite, // 要恢复到的目标 DB
|
||||
sqlite.getPath() + "-backup", // 备份文件
|
||||
DB_PASSWORD.getBytes() // 加密备份文件的密钥,非 DB 密钥
|
||||
);
|
||||
int result = recover.run(false); // fatal 参数传 false 表示遇到错误忽略并继续,
|
||||
// 若传 true 遇到错误则中止并返回 FAILED
|
||||
switch (result) {
|
||||
case RecoverKit.RESULT_OK:
|
||||
/* 成功 */
|
||||
Log.e("qj","sRoomDatabaseCallback==RecoverKit成功");
|
||||
return true;
|
||||
case RecoverKit.RESULT_CANCELED: /* 取消操作 */
|
||||
Log.e("qj","sRoomDatabaseCallback==RecoverKit取消操作");
|
||||
break;
|
||||
case RecoverKit.RESULT_FAILED: /* 失败 */
|
||||
Log.e("qj","sRoomDatabaseCallback==RecoverKit失败");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
recover.release();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 备份数据
|
||||
*/
|
||||
protected boolean backup() {
|
||||
Log.e("qj", "sRoomDatabaseCallback===backup==start");
|
||||
if (INSTANCE != null) {
|
||||
//备份文件
|
||||
SQLiteDatabase sqlite = ((WCDBDatabase) INSTANCE.getOpenHelper().getWritableDatabase()).getInnerDatabase();
|
||||
BackupKit backup = new BackupKit(
|
||||
sqlite, // 要备份的 DB
|
||||
sqlite.getPath() + "-backup", // 备份文件
|
||||
"123456".getBytes(), // 加密备份文件的密钥,非 DB 密钥
|
||||
0, null);
|
||||
int result = backup.run();
|
||||
switch (result) {
|
||||
case BackupKit.RESULT_OK:
|
||||
/* 成功 */
|
||||
Log.e("qj", "sRoomDatabaseCallback==成功");
|
||||
return true;
|
||||
case BackupKit.RESULT_CANCELED:
|
||||
/* 取消操作 */
|
||||
Log.e("qj", "sRoomDatabaseCallback==取消操作");
|
||||
break;
|
||||
case BackupKit.RESULT_FAILED:
|
||||
/* 失败 */
|
||||
Log.e("qj", "sRoomDatabaseCallback==失败");
|
||||
break;
|
||||
}
|
||||
|
||||
backup.release();
|
||||
}
|
||||
Log.e("qj", "sRoomDatabaseCallback===backup==end");
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void release() {
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
package com.navinfo.omqs.ui.activity.map
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.navigation.findNavController
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.collect.library.map.handler.NiLocationListener
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.databinding.ActivityMainBinding
|
||||
import com.navinfo.omqs.db.TraceDataBase
|
||||
import com.navinfo.omqs.http.offlinemapdownload.OfflineMapDownloadManager
|
||||
import com.navinfo.omqs.system.SystemConstant
|
||||
import com.navinfo.omqs.ui.activity.BaseActivity
|
||||
@@ -50,7 +47,8 @@ class MainActivity : BaseActivity() {
|
||||
this,
|
||||
binding.mainActivityMap,
|
||||
null,
|
||||
Constant.MAP_PATH
|
||||
Constant.MAP_PATH,
|
||||
Constant.DATA_PATH+ SystemConstant.USER_ID+"/trace.sqlite"
|
||||
)
|
||||
//关联生命周期
|
||||
binding.lifecycleOwner = this
|
||||
@@ -78,6 +76,7 @@ class MainActivity : BaseActivity() {
|
||||
})
|
||||
//显示轨迹图层
|
||||
// mapController.layerManagerHandler.showNiLocationLayer(Constant.DATA_PATH+ SystemConstant.USER_ID+"/trace.sqlite")
|
||||
mapController.layerManagerHandler.showNiLocationLayer()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@@ -108,6 +107,8 @@ class MainActivity : BaseActivity() {
|
||||
*/
|
||||
fun openCamera() {
|
||||
binding.viewModel!!.onClickCameraButton(this)
|
||||
//显示轨迹图层
|
||||
//binding!!.viewModel!!.onClickCameraButton(this)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.navigation.findNavController
|
||||
import com.blankj.utilcode.util.ToastUtils
|
||||
import com.navinfo.collect.library.data.dao.impl.TraceDataBase
|
||||
import com.navinfo.collect.library.data.entity.NiLocation
|
||||
import com.navinfo.collect.library.map.NIMapController
|
||||
import com.navinfo.collect.library.map.handler.OnQsRecordItemClickListener
|
||||
@@ -15,12 +16,12 @@ import com.navinfo.collect.library.utils.GeometryTools
|
||||
import com.navinfo.collect.library.utils.GeometryToolsKt
|
||||
import com.navinfo.omqs.Constant
|
||||
import com.navinfo.omqs.R
|
||||
import com.navinfo.omqs.db.TraceDataBase
|
||||
import com.navinfo.omqs.system.SystemConstant
|
||||
import com.navinfo.omqs.ui.dialog.CommonDialog
|
||||
import com.navinfo.omqs.ui.manager.TakePhotoManager
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.realm.RealmSet
|
||||
import org.oscim.core.GeoPoint
|
||||
import org.videolan.libvlc.LibVlcUtil
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -105,10 +106,7 @@ class MainViewModel @Inject constructor(
|
||||
if (niLocationList != null && niLocationList.size > 0) {
|
||||
|
||||
var niLocation = niLocationList[0]
|
||||
var doubleArray = doubleArrayOf()
|
||||
doubleArray[0] = niLocation.longitude
|
||||
doubleArray[1] = niLocation.latitude
|
||||
val geometry = GeometryTools.createGeometry(doubleArray)
|
||||
val geometry = GeometryTools.createGeometry(GeoPoint(niLocation.latitude,niLocation.longitude))
|
||||
val tileX = RealmSet<Int>()
|
||||
GeometryToolsKt.getTileXByGeometry(geometry.toString(), tileX)
|
||||
val tileY = RealmSet<Int>()
|
||||
|
||||
@@ -225,7 +225,9 @@ class PersonalCenterViewModel @Inject constructor(
|
||||
|
||||
fun readRealmData() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
realmOperateHelper.queryLink(GeometryTools.createPoint(115.685817,28.62759))
|
||||
// val result = realmOperateHelper.queryLink(GeometryTools.createPoint(115.685817,28.62759))
|
||||
val result = realmOperateHelper.queryLinkByLinkPid("84206617008217069")
|
||||
Log.d("xiaoyan", result.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user