Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -27,16 +27,15 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
|
||||||
implementation rootProject.ext.dependencies.androidxccorektx
|
implementation rootProject.ext.dependencies.androidxccorektx
|
||||||
implementation rootProject.ext.dependencies.androidxappcompat
|
implementation rootProject.ext.dependencies.androidxappcompat
|
||||||
|
implementation rootProject.ext.dependencies.okhttpinterceptor
|
||||||
api rootProject.ext.dependencies.retrofit
|
api rootProject.ext.dependencies.retrofit
|
||||||
api rootProject.ext.dependencies.retrofitadapter
|
api rootProject.ext.dependencies.retrofitadapter
|
||||||
api rootProject.ext.dependencies.retrofitconvertergson
|
api rootProject.ext.dependencies.retrofitconvertergson
|
||||||
api rootProject.ext.dependencies.retrofitconverterscalars
|
api rootProject.ext.dependencies.retrofitconverterscalars
|
||||||
|
|
||||||
implementation project(path: ':foudations:mogo-httpdns')
|
implementation project(path: ':foudations:mogo-httpdns')
|
||||||
implementation project(path: ':foudations:mogo-passport')
|
implementation project(path: ':foudations:mogo-passport')
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,10 @@ import com.mogo.cloud.commons.network.NetConstants.Companion.CONNECT_TIMEOUT
|
|||||||
import com.mogo.cloud.commons.network.NetConstants.Companion.READ_TIMEOUT
|
import com.mogo.cloud.commons.network.NetConstants.Companion.READ_TIMEOUT
|
||||||
import com.mogo.cloud.commons.network.NetConstants.Companion.WRITE_TIMEOUT
|
import com.mogo.cloud.commons.network.NetConstants.Companion.WRITE_TIMEOUT
|
||||||
import com.mogo.cloud.commons.network.interceptor.HeaderNetworkInterceptor
|
import com.mogo.cloud.commons.network.interceptor.HeaderNetworkInterceptor
|
||||||
import com.mogo.cloud.commons.network.interceptor.RequestLogInterceptor
|
|
||||||
import com.mogo.cloud.commons.network.interceptor.ResponseLogInterceptor
|
|
||||||
import com.mogo.cloud.commons.utils.lookup
|
import com.mogo.cloud.commons.utils.lookup
|
||||||
import okhttp3.Dns
|
import okhttp3.Dns
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@@ -23,8 +22,7 @@ class OkHttpFactory private constructor() {
|
|||||||
companion object {
|
companion object {
|
||||||
val okHttpClient: OkHttpClient by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
val okHttpClient: OkHttpClient by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||||
OkHttpClient.Builder()
|
OkHttpClient.Builder()
|
||||||
.addInterceptor(RequestLogInterceptor())
|
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
|
||||||
.addInterceptor(ResponseLogInterceptor())
|
|
||||||
.addNetworkInterceptor(HeaderNetworkInterceptor())
|
.addNetworkInterceptor(HeaderNetworkInterceptor())
|
||||||
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
|
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
|
|||||||
@@ -46,4 +46,6 @@ object RetrofitFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
package com.mogo.cloud.commons.network.interceptor
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.Protocol
|
|
||||||
import okhttp3.Response
|
|
||||||
import okio.Buffer
|
|
||||||
import java.io.IOException
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
/**
|
|
||||||
* created by wujifei on 2021/1/20 10:48
|
|
||||||
* describe:
|
|
||||||
*/
|
|
||||||
class RequestLogInterceptor : Interceptor {
|
|
||||||
private val TAG = "RequestLogInterceptor"
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
|
||||||
val request = chain.request()
|
|
||||||
val requestBody = request.body()
|
|
||||||
val hasRequestBody = requestBody != null
|
|
||||||
|
|
||||||
var protocol = Protocol.HTTP_1_1.toString()
|
|
||||||
if (chain.connection() != null && chain.connection()!!.protocol() != null) {
|
|
||||||
protocol = chain.connection()!!.protocol().toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
val logMsg = StringBuilder()
|
|
||||||
logMsg.append("--> ")
|
|
||||||
logMsg.append(protocol).append(", ")
|
|
||||||
logMsg.append(request.method()).append(", ")
|
|
||||||
logMsg.append("Request Headers: ").append(request.headers()).append("\r\n")
|
|
||||||
logMsg.append(request.url()).append("\r\n")
|
|
||||||
if (hasRequestBody) {
|
|
||||||
logMsg.append("Content-Type: ").append(requestBody!!.contentType()).append(", ")
|
|
||||||
logMsg.append("\r\nContent-Length: ").append(requestBody!!.contentLength())
|
|
||||||
try {
|
|
||||||
var body: String? = null
|
|
||||||
val UTF8 = Charset.forName("UTF-8")
|
|
||||||
val buffer = Buffer()
|
|
||||||
requestBody!!.writeTo(buffer)
|
|
||||||
var charset = UTF8
|
|
||||||
val contentType = requestBody!!.contentType()
|
|
||||||
if (contentType != null) {
|
|
||||||
charset = contentType.charset(UTF8)
|
|
||||||
}
|
|
||||||
if (charset != null) {
|
|
||||||
body = buffer.readString(charset)
|
|
||||||
}
|
|
||||||
logMsg.append("\r\nContent-body: ").append(body)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logMsg.append("\r\n<-- end http request")
|
|
||||||
Log.d(TAG, logMsg.toString())
|
|
||||||
return chain.proceed(request)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.mogo.cloud.commons.network.interceptor
|
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.MediaType
|
|
||||||
import okhttp3.Response
|
|
||||||
import okhttp3.ResponseBody
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* created by wujifei on 2021/1/20 10:50
|
|
||||||
* describe:
|
|
||||||
*/
|
|
||||||
class ResponseLogInterceptor : Interceptor {
|
|
||||||
private val TAG = "ResponseLogInterceptor"
|
|
||||||
override fun intercept(chain: Interceptor.Chain): Response {
|
|
||||||
val startTime = System.nanoTime()
|
|
||||||
val response = chain.proceed(chain.request())
|
|
||||||
val endTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)
|
|
||||||
|
|
||||||
val responseBody = response.body()
|
|
||||||
var responseContent: String? = null
|
|
||||||
var bodySize: String? = null
|
|
||||||
var contentType: MediaType? = null
|
|
||||||
var consumedResponse = false
|
|
||||||
|
|
||||||
val logMsg = StringBuilder()
|
|
||||||
|
|
||||||
if (responseBody != null) {
|
|
||||||
val contentLength = responseBody.contentLength()
|
|
||||||
bodySize = if (contentLength != -1L) "$contentLength-byte" else "unknown-length"
|
|
||||||
contentType = responseBody.contentType()
|
|
||||||
responseContent = responseBody.string()
|
|
||||||
consumedResponse = true
|
|
||||||
}
|
|
||||||
|
|
||||||
logMsg.append("--> ")
|
|
||||||
logMsg.append(response.code()).append(" ")
|
|
||||||
logMsg.append(response.message()).append(" ")
|
|
||||||
logMsg.append(response.protocol()).append(" ")
|
|
||||||
logMsg.append(response.request().url()).append("\r\n")
|
|
||||||
logMsg.append("Response Content: ").append(responseContent).append("\r\n")
|
|
||||||
logMsg.append("Content-Type: ").append(contentType).append(", ")
|
|
||||||
logMsg.append("Content-Length: ").append(bodySize).append(", ")
|
|
||||||
logMsg.append(" (").append(endTime).append("ms)")
|
|
||||||
logMsg.append(" <-- end http response")
|
|
||||||
|
|
||||||
Log.d(TAG, logMsg.toString())
|
|
||||||
|
|
||||||
|
|
||||||
return if (consumedResponse) response.newBuilder().body(ResponseBody.create(contentType, responseContent)).build() else response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package com.mogo.cloud.commons.utils
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.ConnectivityManager
|
|
||||||
import android.net.NetworkInfo
|
|
||||||
|
|
||||||
/**
|
|
||||||
* created by wujifei on 2021/1/20 11:04
|
|
||||||
* describe:
|
|
||||||
*/
|
|
||||||
class CheckUtils {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* 网络是否可用
|
|
||||||
*/
|
|
||||||
fun isNetworkConnected(context: Context?): Boolean {
|
|
||||||
if (context == null) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
||||||
var network: NetworkInfo? = null
|
|
||||||
if (cm != null) {
|
|
||||||
network = cm.activeNetworkInfo
|
|
||||||
}
|
|
||||||
return network != null && network.isAvailable && network.isConnected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package com.mogo.cloud.commons.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author donghongyu
|
||||||
|
*/
|
||||||
|
public class CoordinateUtils {
|
||||||
|
|
||||||
|
private static double a = 6378245.0;
|
||||||
|
private static double ee = 0.00669342162296594323;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机GPS坐标转火星坐标
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static double[] transformFromWGSToGCJ( double lat, double lon ) {
|
||||||
|
|
||||||
|
//如果在国外,则默认不进行转换
|
||||||
|
if ( outOfChina( lat, lon ) ) {
|
||||||
|
return new double[]{lat, lon};
|
||||||
|
}
|
||||||
|
double dLat = transformLat( lon - 105.0, lat - 35.0 );
|
||||||
|
double dLon = transformLon( lon - 105.0, lat - 35.0 );
|
||||||
|
double radLat = lat / 180.0 * Math.PI;
|
||||||
|
double magic = Math.sin( radLat );
|
||||||
|
magic = 1 - ee * magic * magic;
|
||||||
|
double sqrtMagic = Math.sqrt( magic );
|
||||||
|
dLat = ( dLat * 180.0 ) / ( ( a * ( 1 - ee ) ) / ( magic * sqrtMagic ) * Math.PI );
|
||||||
|
dLon = ( dLon * 180.0 ) / ( a / sqrtMagic * Math.cos( radLat ) * Math.PI );
|
||||||
|
|
||||||
|
return new double[]{lat + dLat, lon + dLon};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double transformLat( double x, double y ) {
|
||||||
|
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt( x > 0 ? x : -x );
|
||||||
|
ret += ( 20.0 * Math.sin( 6.0 * x * Math.PI ) + 20.0 * Math.sin( 2.0 * x * Math.PI ) ) * 2.0 / 3.0;
|
||||||
|
ret += ( 20.0 * Math.sin( y * Math.PI ) + 40.0 * Math.sin( y / 3.0 * Math.PI ) ) * 2.0 / 3.0;
|
||||||
|
ret += ( 160.0 * Math.sin( y / 12.0 * Math.PI ) + 320 * Math.sin( y * Math.PI / 30.0 ) ) * 2.0 / 3.0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double transformLon( double x, double y ) {
|
||||||
|
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt( x > 0 ? x : -x );
|
||||||
|
ret += ( 20.0 * Math.sin( 6.0 * x * Math.PI ) + 20.0 * Math.sin( 2.0 * x * Math.PI ) ) * 2.0 / 3.0;
|
||||||
|
ret += ( 20.0 * Math.sin( x * Math.PI ) + 40.0 * Math.sin( x / 3.0 * Math.PI ) ) * 2.0 / 3.0;
|
||||||
|
ret += ( 150.0 * Math.sin( x / 12.0 * Math.PI ) + 300.0 * Math.sin( x / 30.0 * Math.PI ) ) * 2.0 / 3.0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean outOfChina( double lat, double lon ) {
|
||||||
|
if ( lon < 72.004 || lon > 137.8347 )
|
||||||
|
return true;
|
||||||
|
if ( lat < 0.8293 || lat > 55.8271 )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final double[] transformGcj02toWgs84( double lat, double lng ) {
|
||||||
|
double[] var10000;
|
||||||
|
if ( outOfChina( lat, lng ) ) {
|
||||||
|
var10000 = new double[]{lng, lat};
|
||||||
|
} else {
|
||||||
|
double dlat = transformLat( lng - 105.0D, lat - 35.0D );
|
||||||
|
double dlng = transformLon( lng - 105.0D, lat - 35.0D );
|
||||||
|
double radlat = lat / 180.0D * Math.PI;
|
||||||
|
double magic = Math.sin( radlat );
|
||||||
|
magic = ( double ) 1 - 0.006693421622965943D * magic * magic;
|
||||||
|
double sqrtmagic = Math.sqrt( magic );
|
||||||
|
dlat = dlat * 180.0D / ( 6335552.717000426D / ( magic * sqrtmagic ) * Math.PI );
|
||||||
|
dlng = dlng * 180.0D / ( 6378245.0D / sqrtmagic * Math.cos( radlat ) * Math.PI );
|
||||||
|
double mglat = lat + dlat;
|
||||||
|
double mglng = lng + dlng;
|
||||||
|
var10000 = new double[]{lng * ( double ) 2 - mglng, lat * ( double ) 2 - mglat};
|
||||||
|
}
|
||||||
|
|
||||||
|
return var10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param lon1
|
||||||
|
* @param lat1
|
||||||
|
* @param lon2
|
||||||
|
* @param lat2
|
||||||
|
* @return 两坐标的距离 单位:米(M)
|
||||||
|
*/
|
||||||
|
public static float calculateLineDistance( double lon1, double lat1, double lon2, double lat2 ) {
|
||||||
|
try {
|
||||||
|
double var2 = lon1;
|
||||||
|
double var4 = lat1;
|
||||||
|
double var6 = lon2;
|
||||||
|
double var8 = lat2;
|
||||||
|
var2 *= 0.01745329251994329D;
|
||||||
|
var4 *= 0.01745329251994329D;
|
||||||
|
var6 *= 0.01745329251994329D;
|
||||||
|
var8 *= 0.01745329251994329D;
|
||||||
|
double var10 = Math.sin( var2 );
|
||||||
|
double var12 = Math.sin( var4 );
|
||||||
|
double var14 = Math.cos( var2 );
|
||||||
|
double var16 = Math.cos( var4 );
|
||||||
|
double var18 = Math.sin( var6 );
|
||||||
|
double var20 = Math.sin( var8 );
|
||||||
|
double var22 = Math.cos( var6 );
|
||||||
|
double var24 = Math.cos( var8 );
|
||||||
|
double[] var28 = new double[3];
|
||||||
|
double[] var29 = new double[3];
|
||||||
|
var28[0] = var16 * var14;
|
||||||
|
var28[1] = var16 * var10;
|
||||||
|
var28[2] = var12;
|
||||||
|
var29[0] = var24 * var22;
|
||||||
|
var29[1] = var24 * var18;
|
||||||
|
var29[2] = var20;
|
||||||
|
return ( float ) ( Math.asin( Math.sqrt( ( var28[0] - var29[0] ) * ( var28[0] - var29[0] ) + ( var28[1] - var29[1] ) * ( var28[1] - var29[1] ) + ( var28[2] - var29[2] ) * ( var28[2] - var29[2] ) ) / 2.0D ) * 1.27420015798544E7D );
|
||||||
|
} catch ( Throwable var26 ) {
|
||||||
|
var26.printStackTrace();
|
||||||
|
return 0.0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,8 +25,9 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation project(path: ':foudations:mogo-passport')
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||||
|
implementation project(":foudations:mogo-commons")
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.mogo.realtime.InterfaceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liujing
|
||||||
|
* @description 描述
|
||||||
|
* @since: 2021/1/21
|
||||||
|
*/
|
||||||
|
public final class RealTimeApisHandler {
|
||||||
|
private static volatile RealTimeApisHandler sInstance;
|
||||||
|
private static volatile RealTimeServiceApis sApis;
|
||||||
|
|
||||||
|
public static RealTimeApisHandler getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
synchronized (RealTimeApisHandler.class) {
|
||||||
|
sInstance = new RealTimeApisHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RealTimeServiceApis getApis(){
|
||||||
|
if (sApis == null){
|
||||||
|
synchronized (this){
|
||||||
|
// sApis = new RealTimeServiceApis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sApis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.mogo.realtime.InterfaceManager;
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.ADASRecognizedResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liujing
|
||||||
|
* @description 描述
|
||||||
|
* @since: 2021/1/21
|
||||||
|
*/
|
||||||
|
public interface RealTimeServiceApis {
|
||||||
|
RecognizedResultProvider getRecognizedResultManager();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.mogo.realtime.InterfaceManager;
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.ADASRecognizedResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author liujing
|
||||||
|
* @description 描述
|
||||||
|
* @since: 2021/1/21
|
||||||
|
*/
|
||||||
|
public interface RecognizedResultProvider {
|
||||||
|
/**
|
||||||
|
* 获取 adas 识别列表
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<ADASRecognizedResult> getLastADASRecognizedResult();
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package com.mogo.realtime.constant;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.mogo.cloud.passport.MoGoAiCloudClient;
|
||||||
|
import com.mogo.realtime.InterfaceManager.RealTimeApisHandler;
|
||||||
|
import com.mogo.realtime.InterfaceManager.RealTimeServiceApis;
|
||||||
|
import com.mogo.realtime.entity.ADASRecognizedResult;
|
||||||
|
import com.mogo.realtime.entity.CloudLocationInfo;
|
||||||
|
import com.mogo.realtime.location.LocationResult;
|
||||||
|
import com.mogo.realtime.location.MogoRTKLocation;
|
||||||
|
import com.mogo.realtime.util.MortonCode;
|
||||||
|
import com.mogo.realtime.util.SimpleLocationCorrectStrategy;
|
||||||
|
import com.mogo.realtime.websocket.OnePerSecondSendContent;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author congtaowang
|
||||||
|
* @since 2020/12/14
|
||||||
|
* <p>
|
||||||
|
* 实时上报坐标、识别物体
|
||||||
|
*/
|
||||||
|
public class SnapshotUploadInTime implements MogoRTKLocation.RTKLocationListener {
|
||||||
|
|
||||||
|
private static final String TAG = "SnapshotUploadInTime";
|
||||||
|
|
||||||
|
private static volatile SnapshotUploadInTime sInstance;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
private SnapshotUploadInTime() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SnapshotUploadInTime getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
synchronized (SnapshotUploadInTime.class) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new SnapshotUploadInTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void release() {
|
||||||
|
sInstance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object readResolve() {
|
||||||
|
// 阻止反序列化,必须实现 Serializable 接口
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(Context context) {
|
||||||
|
mContext = context.getApplicationContext();
|
||||||
|
MogoRTKLocation.getInstance().registerRTKLocationListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
MogoRTKLocation.getInstance().unregisterRTKLocationListener();
|
||||||
|
MogoRTKLocation.getInstance().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(List<CloudLocationInfo> cloudLocationInfos) {
|
||||||
|
startSendCarLocationAndAdasRecognizedResult2Server(cloudLocationInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CloudLocationInfo mLastInfo;
|
||||||
|
|
||||||
|
private void startSendCarLocationAndAdasRecognizedResult2Server(List<CloudLocationInfo> cloudLocationInfo) {
|
||||||
|
CloudLocationInfo lastInfo = null;
|
||||||
|
// 如果数组内容不为空,就用数组最后一个值
|
||||||
|
if (cloudLocationInfo != null && !cloudLocationInfo.isEmpty()) {
|
||||||
|
lastInfo = cloudLocationInfo.get(cloudLocationInfo.size() - 1);
|
||||||
|
mLastInfo = lastInfo;
|
||||||
|
}
|
||||||
|
if (lastInfo == null) {
|
||||||
|
lastInfo = mLastInfo;
|
||||||
|
}
|
||||||
|
LocationResult locationResult = null;
|
||||||
|
if (lastInfo != null) {
|
||||||
|
// 定位点预测纠偏
|
||||||
|
lastInfo = SimpleLocationCorrectStrategy.getInstance().correct(lastInfo);
|
||||||
|
locationResult = new LocationResult();
|
||||||
|
if (lastInfo != null) {
|
||||||
|
locationResult.lastCoordinate = lastInfo;
|
||||||
|
locationResult.mortonCode = MortonCode.wrapEncodeMorton(lastInfo.getLon(), lastInfo.getLat());
|
||||||
|
}
|
||||||
|
// locationResult.coordinates = new ArrayList<>();
|
||||||
|
locationResult.sn = MoGoAiCloudClient.getInstance().getAiCloudClientConfig().getSn();
|
||||||
|
// if ( cloudLocationInfo == null ) {
|
||||||
|
// locationResult.coordinates.addAll( new ArrayList<>() );
|
||||||
|
// } else {
|
||||||
|
// locationResult.coordinates.addAll( cloudLocationInfo );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
List<ADASRecognizedResult> recognizedResults = RealTimeApisHandler.getInstance().getApis().getRecognizedResultManager().getLastADASRecognizedResult();//外显接口返回
|
||||||
|
OnePerSecondSendContent content = new OnePerSecondSendContent();
|
||||||
|
content.self = locationResult;
|
||||||
|
content.adas = recognizedResults;
|
||||||
|
|
||||||
|
if (content.self == null &&
|
||||||
|
(content.adas == null || content.adas.isEmpty())) {
|
||||||
|
Log.d(TAG, "no information 2 sent");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//备注
|
||||||
|
/*
|
||||||
|
等钟超SocketManagerSDK
|
||||||
|
*
|
||||||
|
MarkerServiceHandler.getApis().getWebSocketManagerApi( mContext ).sendMsg( content, new IMogoOnWebSocketMessageListener() {
|
||||||
|
@Override
|
||||||
|
public WebSocketMsgType getDownLinkType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WebSocketMsgType getUpLinkType() {
|
||||||
|
return WebSocketMsgType.MSG_TYPE_UPLINK_CAR_DATA;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.mogo.realtime.entity;
|
||||||
|
|
||||||
|
public
|
||||||
|
/**
|
||||||
|
* @author congtaowang
|
||||||
|
* @since 2020/10/25
|
||||||
|
*
|
||||||
|
* adas 识别物体参数
|
||||||
|
*/
|
||||||
|
class ADASRecognizedResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别物体类型
|
||||||
|
*/
|
||||||
|
public int type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别物体唯一标识
|
||||||
|
*/
|
||||||
|
public String uuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 红绿灯颜色
|
||||||
|
*/
|
||||||
|
public String color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public String carId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别物体的纬度
|
||||||
|
*/
|
||||||
|
public double lat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 识别物体的经度
|
||||||
|
*/
|
||||||
|
public double lon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 朝向
|
||||||
|
*/
|
||||||
|
public double heading;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统时间
|
||||||
|
*/
|
||||||
|
public long systemTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定位卫星时间
|
||||||
|
*/
|
||||||
|
public long satelliteTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 海拔
|
||||||
|
*/
|
||||||
|
public double alt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 速度
|
||||||
|
*/
|
||||||
|
public double speed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 莫顿码
|
||||||
|
*/
|
||||||
|
public long mortonCode;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
package com.mogo.realtime.entity;
|
||||||
|
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import com.mogo.utils.CoordinateUtils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云端定位信息和自车定位信息
|
||||||
|
*
|
||||||
|
* @author tongchenfei
|
||||||
|
*/
|
||||||
|
public class CloudLocationInfo implements Parcelable {
|
||||||
|
private double lat;
|
||||||
|
private double lon;
|
||||||
|
private double heading;
|
||||||
|
private long systemTime;
|
||||||
|
private long satelliteTime;
|
||||||
|
private double alt;
|
||||||
|
private double speed;
|
||||||
|
|
||||||
|
public CloudLocationInfo() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public CloudLocationInfo(CloudLocationInfo info ) {
|
||||||
|
this.lat = info.getLat();
|
||||||
|
this.lon = info.getLon();
|
||||||
|
this.heading = info.getHeading();
|
||||||
|
this.systemTime = System.currentTimeMillis();
|
||||||
|
this.satelliteTime = System.currentTimeMillis();
|
||||||
|
this.alt = info.alt;
|
||||||
|
this.speed = info.speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void convertCoor2GCJ02(){
|
||||||
|
double[] amapCoord = CoordinateUtils.transformFromWGSToGCJ( lat, lon );
|
||||||
|
if ( amapCoord != null ) {
|
||||||
|
this.lat = amapCoord[0];
|
||||||
|
this.lon = amapCoord[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CloudLocationInfo(Parcel in ) {
|
||||||
|
lat = in.readDouble();
|
||||||
|
lon = in.readDouble();
|
||||||
|
heading = in.readDouble();
|
||||||
|
systemTime = in.readLong();
|
||||||
|
satelliteTime = in.readLong();
|
||||||
|
alt = in.readDouble();
|
||||||
|
speed = in.readDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel( Parcel dest, int flags ) {
|
||||||
|
dest.writeDouble( lat );
|
||||||
|
dest.writeDouble( lon );
|
||||||
|
dest.writeDouble( heading );
|
||||||
|
dest.writeLong( systemTime );
|
||||||
|
dest.writeLong( satelliteTime );
|
||||||
|
dest.writeDouble( alt );
|
||||||
|
dest.writeDouble( speed );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator< CloudLocationInfo > CREATOR = new Creator< CloudLocationInfo >() {
|
||||||
|
@Override
|
||||||
|
public CloudLocationInfo createFromParcel( Parcel in ) {
|
||||||
|
return new CloudLocationInfo( in );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloudLocationInfo[] newArray( int size ) {
|
||||||
|
return new CloudLocationInfo[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public double getLat() {
|
||||||
|
return lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLat( double lat ) {
|
||||||
|
this.lat = lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLon() {
|
||||||
|
return lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLon( double lon ) {
|
||||||
|
this.lon = lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getHeading() {
|
||||||
|
return heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeading( double heading ) {
|
||||||
|
this.heading = heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSystemTime() {
|
||||||
|
return systemTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSystemTime( long systemTime ) {
|
||||||
|
this.systemTime = systemTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSatelliteTime() {
|
||||||
|
return satelliteTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSatelliteTime( long satelliteTime ) {
|
||||||
|
this.satelliteTime = satelliteTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getAlt() {
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlt( double alt ) {
|
||||||
|
this.alt = alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getSpeed() {
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpeed( double speed ) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CloudLocationInfo{" +
|
||||||
|
"lat=" + lat +
|
||||||
|
", lon=" + lon +
|
||||||
|
", heading=" + heading +
|
||||||
|
", systemTime=" + systemTime +
|
||||||
|
", satelliteTime=" + satelliteTime +
|
||||||
|
", alt=" + alt +
|
||||||
|
", speed=" + speed +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public String print() {
|
||||||
|
return "CloudLocation{ lon: " + lon + " lat: " + lat + " heading: " + heading + " speed: "
|
||||||
|
+ speed + "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals( Object o ) {
|
||||||
|
if ( this == o ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ( o == null || getClass() != o.getClass() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
CloudLocationInfo that = ( CloudLocationInfo ) o;
|
||||||
|
return Double.compare( that.lat, lat ) == 0 &&
|
||||||
|
Double.compare( that.lon, lon ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash( lat, lon );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.mogo.realtime.location;
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.CloudLocationInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public
|
||||||
|
/**
|
||||||
|
* @author congtaowang
|
||||||
|
* @since 2020/10/25
|
||||||
|
*
|
||||||
|
* 自车定位信息
|
||||||
|
*/
|
||||||
|
class LocationResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sn
|
||||||
|
*/
|
||||||
|
public String sn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后一个定位点的莫顿码
|
||||||
|
*/
|
||||||
|
public long mortonCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后一个定位点
|
||||||
|
*/
|
||||||
|
public CloudLocationInfo lastCoordinate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1s 内的连续定位点
|
||||||
|
*/
|
||||||
|
public List< CloudLocationInfo > coordinates;
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
package com.mogo.realtime.location;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.location.Criteria;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationListener;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.CloudLocationInfo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class MogoRTKLocation {
|
||||||
|
|
||||||
|
private static final String TAG = "MogoRTKLocation";
|
||||||
|
private static final int MSG_DATA_CHANGED = 0x100;
|
||||||
|
private static final long MSG_DATA_INTERNAL = 500L;
|
||||||
|
|
||||||
|
private Handler mHandler;
|
||||||
|
private LocationManager locationManager;
|
||||||
|
private RTKLocationListener rtkLocationListener;
|
||||||
|
private List<CloudLocationInfo> cacheList = new ArrayList<>();
|
||||||
|
|
||||||
|
public static MogoRTKLocation getInstance() {
|
||||||
|
return RTKHolder.rtkLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RTKHolder {
|
||||||
|
private static final MogoRTKLocation rtkLoc = new MogoRTKLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MogoRTKLocation() {
|
||||||
|
mHandler = new Handler(WorkThreadHandler.newInstance( TAG ).getLooper() ) {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
super.handleMessage(msg);
|
||||||
|
if (msg.what == MSG_DATA_CHANGED) {
|
||||||
|
mHandler.sendEmptyMessageDelayed(MSG_DATA_CHANGED, uploadDelay);
|
||||||
|
sendLocationData();
|
||||||
|
|
||||||
|
// Logger.d(TAG,"handleMessage开始发送消息");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mHandler.sendEmptyMessage(MSG_DATA_CHANGED);
|
||||||
|
Logger.d(TAG,"构造方法开始发送消息");
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface RTKLocationListener {
|
||||||
|
void onLocationChanged(List<CloudLocationInfo> cloudLocationInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendLocationData() {
|
||||||
|
|
||||||
|
if (rtkLocationListener != null) {
|
||||||
|
List<CloudLocationInfo> list = new ArrayList<>(cacheList);
|
||||||
|
rtkLocationListener.onLocationChanged(list);
|
||||||
|
}
|
||||||
|
if (cacheList != null && cacheList.size() > 0) {
|
||||||
|
cacheList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerRTKLocationListener(RTKLocationListener locationListener) {
|
||||||
|
rtkLocationListener = locationListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterRTKLocationListener(){
|
||||||
|
rtkLocationListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
locationManager = (LocationManager) AbsMogoApplication.getApp().getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
String provider = locationManager.getBestProvider(getCriteria(), true);
|
||||||
|
Logger.d(TAG, "init provider : " + provider);
|
||||||
|
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||||
|
try {
|
||||||
|
locationManager.requestLocationUpdates(provider, 0, 0, locationListener);
|
||||||
|
Location location = locationManager.getLastKnownLocation(provider);
|
||||||
|
if (location != null) {
|
||||||
|
Logger.i(TAG, "location : " + location.toString());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Logger.d(TAG, "RTK LocationManager requestLocationUpdates has Exception : " + e.getMessage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Logger.d(TAG, "RTK LocationManager Provider GPS_PROVIDER unable");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册修改上报间隔的广播, 临时使用,后面可直接干掉,发送广播的地方在EntranceFragment
|
||||||
|
IntentFilter filter = new IntentFilter("com.mogo.launcher.action.FIX_UPLOAT_DELAY");
|
||||||
|
AbsMogoApplication.getApp().registerReceiver(fixUploadDelayReceiver, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Criteria getCriteria() {
|
||||||
|
Criteria criteria = new Criteria();
|
||||||
|
criteria.setAccuracy(Criteria.ACCURACY_FINE); //高精
|
||||||
|
criteria.setAltitudeRequired(false);
|
||||||
|
criteria.setBearingRequired(true);
|
||||||
|
criteria.setSpeedRequired(true);
|
||||||
|
criteria.setPowerRequirement(Criteria.POWER_LOW);
|
||||||
|
return criteria;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocationListener locationListener = new LocationListener() {
|
||||||
|
@Override
|
||||||
|
public void onLocationChanged(Location location) {
|
||||||
|
if (location != null) {
|
||||||
|
CloudLocationInfo cloudLocationInfo = new CloudLocationInfo();
|
||||||
|
cloudLocationInfo.setAlt(location.getAltitude());
|
||||||
|
cloudLocationInfo.setHeading(location.getBearing());
|
||||||
|
cloudLocationInfo.setLat(location.getLatitude());
|
||||||
|
cloudLocationInfo.setLon(location.getLongitude());
|
||||||
|
cloudLocationInfo.setSpeed(location.getSpeed());
|
||||||
|
cloudLocationInfo.setSatelliteTime(location.getTime());
|
||||||
|
cloudLocationInfo.setSystemTime(System.currentTimeMillis());
|
||||||
|
cloudLocationInfo.convertCoor2GCJ02();
|
||||||
|
cacheList.add(cloudLocationInfo);
|
||||||
|
} else {
|
||||||
|
Logger.e(TAG, "location == null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||||
|
Logger.d(TAG, "onStatusChanged status: " + status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProviderEnabled(String provider) {
|
||||||
|
Logger.d(TAG, "onProviderEnabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProviderDisabled(String provider) {
|
||||||
|
Logger.d(TAG, "onProviderEnabled");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
Logger.d(TAG, "stop RTK Location");
|
||||||
|
if (locationManager != null && locationListener != null) {
|
||||||
|
locationManager.removeUpdates(locationListener);
|
||||||
|
} else {
|
||||||
|
Logger.d(TAG, "stop failed , reason : loc" + locationManager + " , or loc listener: " + locationListener + " is null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long uploadDelay = MSG_DATA_INTERNAL;
|
||||||
|
|
||||||
|
private FixUploadDelayReceiver fixUploadDelayReceiver = new FixUploadDelayReceiver();
|
||||||
|
|
||||||
|
private class FixUploadDelayReceiver extends BroadcastReceiver{
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
uploadDelay = intent.getIntExtra("fixTime", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认保持{@link #uploadDelay}间隔进行位置上报,如遇服务端控制,进行上报间隔修改
|
||||||
|
* @param delay 上报间隔
|
||||||
|
*/
|
||||||
|
public void resetUploadDelay(long delay) {
|
||||||
|
if (mHandler != null && mHandler.hasMessages(MSG_DATA_CHANGED)) {
|
||||||
|
mHandler.removeMessages(MSG_DATA_CHANGED);
|
||||||
|
mHandler.sendEmptyMessageDelayed(MSG_DATA_CHANGED, delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package com.mogo.realtime.util;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 莫顿编码
|
||||||
|
*
|
||||||
|
* @author linyang
|
||||||
|
* @since 2020.07.09
|
||||||
|
*/
|
||||||
|
public class MortonCode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* morton 转 经纬度 时的中间常量
|
||||||
|
*/
|
||||||
|
private static final long NDS_180_DEGREES = 0x7fffffff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* morton 转 经纬度 时的中间常量
|
||||||
|
*/
|
||||||
|
private static final long NDS_360_DEGREES = 4294967295L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* morton 转 经纬度 时的中间常量
|
||||||
|
*/
|
||||||
|
private static final long NDS_90_DEGREES = 0x3fffffff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 经纬度转 morton 时的中间常量
|
||||||
|
*/
|
||||||
|
private static final double RULE_MORTON = Math.pow( 2, 32 ) / 360;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* morton 转 经纬度 时的中间常量
|
||||||
|
*/
|
||||||
|
private static final double RULE_MORTON_TO_LONLAT = 360.0 / Math.pow( 2, 32 );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param lon
|
||||||
|
* @param lat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static long wrapEncodeMorton( Double lon, Double lat ) {
|
||||||
|
DecimalFormat decimalFormat = new DecimalFormat( "#.######" );
|
||||||
|
return encodeMorton( Double.valueOf( decimalFormat.format( lon ) ),
|
||||||
|
Double.valueOf( decimalFormat.format( lat ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编码 morton code
|
||||||
|
*
|
||||||
|
* @param lon
|
||||||
|
* @param lat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static long encodeMorton( Double lon, Double lat ) {
|
||||||
|
|
||||||
|
Long bit = 1L;
|
||||||
|
long mortonCode = 0L;
|
||||||
|
long x = ( long ) ( lon * RULE_MORTON );
|
||||||
|
long y = ( long ) ( lat * RULE_MORTON );
|
||||||
|
|
||||||
|
if ( y < 0 ) {
|
||||||
|
y += 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
y = y << 1;
|
||||||
|
for ( int i = 0; i < 32; i++ ) {
|
||||||
|
// x-part
|
||||||
|
mortonCode = mortonCode | ( x & bit );
|
||||||
|
x = x << 1;
|
||||||
|
bit = bit << 1;
|
||||||
|
// y-part
|
||||||
|
mortonCode = mortonCode | ( y & bit );
|
||||||
|
y = y << 1;
|
||||||
|
bit = bit << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mortonCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将莫顿码解码为坐标
|
||||||
|
*
|
||||||
|
* @param mortonCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static double[] decodeMorton( long mortonCode ) {
|
||||||
|
long[] midPoint = mortonCodeToCoord( mortonCode );
|
||||||
|
normalizeCoord( midPoint );
|
||||||
|
double[] point = new double[2];
|
||||||
|
|
||||||
|
// 将经纬度长整数转化为 浮点类型
|
||||||
|
point[0] = midPoint[0] * RULE_MORTON_TO_LONLAT;
|
||||||
|
point[1] = midPoint[1] * RULE_MORTON_TO_LONLAT;
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 莫顿码分别拆解为 编码后的经纬度长整数
|
||||||
|
*
|
||||||
|
* @param mortonCode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static long[] mortonCodeToCoord( long mortonCode ) {
|
||||||
|
long bit = 1L;
|
||||||
|
long[] longPoint = new long[2];
|
||||||
|
|
||||||
|
for ( int i = 0; i < 32; i++ ) {
|
||||||
|
longPoint[0] |= mortonCode & bit;
|
||||||
|
mortonCode >>= 1;
|
||||||
|
longPoint[1] |= mortonCode & bit;
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
return longPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对编码后的经纬度长整数进行解码
|
||||||
|
*
|
||||||
|
* @param midPoint
|
||||||
|
*/
|
||||||
|
private static void normalizeCoord( long[] midPoint ) {
|
||||||
|
// if x > 180 degrees, then subtract 360 degrees
|
||||||
|
if ( midPoint[0] > NDS_180_DEGREES ) {
|
||||||
|
midPoint[0] -=
|
||||||
|
NDS_360_DEGREES + 1; // add 1 because 0 must be counted as well
|
||||||
|
} else if ( midPoint[0] < -NDS_180_DEGREES ) // if x < 180 , x += 360
|
||||||
|
{
|
||||||
|
midPoint[0] +=
|
||||||
|
NDS_360_DEGREES + 1; // add 1 because 0 must be counted as well
|
||||||
|
}
|
||||||
|
|
||||||
|
// if y > 90 degrees, then subtract 180 degrees
|
||||||
|
if ( midPoint[1] > NDS_90_DEGREES ) {
|
||||||
|
midPoint[1] -=
|
||||||
|
NDS_180_DEGREES + 1; // add 1 because 0 must be counted as well
|
||||||
|
} else if ( midPoint[1] < -NDS_90_DEGREES ) // if y < 90, y += 180
|
||||||
|
{
|
||||||
|
midPoint[1] +=
|
||||||
|
NDS_180_DEGREES + 1; // add 1 because 0 must be counted as well
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
System.out.println( encodeMorton( 116.39584, 39.98152 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
package com.mogo.realtime.util;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import com.mogo.map.MogoLatLng;
|
||||||
|
import com.mogo.module.common.MogoApisHandler;
|
||||||
|
import com.mogo.module.common.entity.CloudLocationInfo;
|
||||||
|
import com.mogo.realtime.entity.CloudLocationInfo;
|
||||||
|
import com.mogo.utils.logger.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定位预测纠错策略
|
||||||
|
*
|
||||||
|
* @author tongchenfei
|
||||||
|
*/
|
||||||
|
public class SimpleLocationCorrectStrategy {
|
||||||
|
private static final String TAG = "SimpleLocationCorrectStrategy";
|
||||||
|
private static final int ERR_COUNT_THRESHOLD = 3;
|
||||||
|
/**
|
||||||
|
* 目标距离误差是10米,就是在原目标距离基础上增加10米
|
||||||
|
*/
|
||||||
|
private static final float TARGET_DISTANCE_DEVIATION = 10;
|
||||||
|
|
||||||
|
private CloudLocationInfo lastLocation = null;
|
||||||
|
private long anchorTime;
|
||||||
|
private int errCount;
|
||||||
|
|
||||||
|
private static SimpleLocationCorrectStrategy instance = new SimpleLocationCorrectStrategy();
|
||||||
|
|
||||||
|
public static SimpleLocationCorrectStrategy getInstance(){
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CloudLocationInfo> historyList = new ArrayList<>();
|
||||||
|
private List<CloudLocationInfo> validList = new ArrayList<>();
|
||||||
|
private List<CloudLocationInfo> correctList = new ArrayList<>();
|
||||||
|
private List<CloudLocationInfo> errList = new ArrayList<>();
|
||||||
|
|
||||||
|
public CloudLocationInfo correct(CloudLocationInfo info) {
|
||||||
|
Logger.d(TAG, "info: " + info.print());
|
||||||
|
if(isLocationValid(info)) {
|
||||||
|
if(recordLocation()) {
|
||||||
|
historyList.add(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastLocation == null) {
|
||||||
|
lastLocation = info;
|
||||||
|
anchorTime = SystemClock.elapsedRealtime();
|
||||||
|
Logger.d(TAG, "第一条数据");
|
||||||
|
if(recordLocation()) {
|
||||||
|
validList.add(lastLocation);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
if (lastLocation.equals(info)) {
|
||||||
|
Logger.d(TAG, "相同坐标点==");
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
float targetDistance =
|
||||||
|
(float) (lastLocation.getSpeed() * (SystemClock.elapsedRealtime() - anchorTime) / 1000) + TARGET_DISTANCE_DEVIATION;
|
||||||
|
float distance = MogoApisHandler.getInstance().getApis().getMapServiceApi().getMapUIController().calculateLineDistance(LocationParseUtil.cloudLocationToMogoLatLng(lastLocation), LocationParseUtil.cloudLocationToMogoLatLng(info));
|
||||||
|
Logger.d(TAG,
|
||||||
|
"准备计算{ lastInfo: " + lastLocation.print() + " info: " + info.print() + " targetDistance: " + targetDistance + " distance : " + distance + "}");
|
||||||
|
if (distance <= targetDistance) {
|
||||||
|
// 新的定位点在目标距离范围内,认为此数据有效
|
||||||
|
lastLocation = info;
|
||||||
|
anchorTime = SystemClock.elapsedRealtime();
|
||||||
|
errCount = 0;
|
||||||
|
Logger.d(TAG, "在范围内,为有效点");
|
||||||
|
if(recordLocation()) {
|
||||||
|
validList.add(lastLocation);
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
} else {
|
||||||
|
// 出现异常点
|
||||||
|
if (errCount >= ERR_COUNT_THRESHOLD) {
|
||||||
|
// 出错次数超过阈值,认为本次出错点为正确点
|
||||||
|
if(recordLocation()) {
|
||||||
|
errList.add(new CloudLocationInfo(lastLocation));
|
||||||
|
correctList.add(info);
|
||||||
|
}
|
||||||
|
lastLocation = info;
|
||||||
|
anchorTime = SystemClock.elapsedRealtime();
|
||||||
|
errCount = 0;
|
||||||
|
Logger.d(TAG, "出错次数超限,异常点变有效点");
|
||||||
|
return info;
|
||||||
|
} else {
|
||||||
|
// 按照上一个点的方向和速度,计算下一个点的位置,下一个点除坐标点外,其余数据与上一个点相同
|
||||||
|
CloudLocationInfo nextInfo = new CloudLocationInfo(lastLocation);
|
||||||
|
MogoLatLng nextLatLon = computerThatLonLat(lastLocation.getLon(),
|
||||||
|
lastLocation.getLat(), lastLocation.getHeading(), targetDistance);
|
||||||
|
nextInfo.setLon(nextLatLon.lon);
|
||||||
|
nextInfo.setLat(nextLatLon.lat);
|
||||||
|
if(recordLocation()) {
|
||||||
|
errList.add(info);
|
||||||
|
correctList.add(nextInfo);
|
||||||
|
}
|
||||||
|
lastLocation = nextInfo;
|
||||||
|
anchorTime = SystemClock.elapsedRealtime();
|
||||||
|
errCount++;
|
||||||
|
Logger.d(TAG, "异常点纠偏 info: " + lastLocation);
|
||||||
|
// return lastLocation;
|
||||||
|
if(recordLocation()) {
|
||||||
|
correctList.add(nextInfo);
|
||||||
|
}
|
||||||
|
return nextInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Logger.e(TAG, e, "纠偏异常");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Logger.d(TAG, "定位点异常");
|
||||||
|
if (lastLocation == null) {
|
||||||
|
return null;
|
||||||
|
}else{
|
||||||
|
try {
|
||||||
|
float targetDistance =
|
||||||
|
(float) (lastLocation.getSpeed() * (SystemClock.elapsedRealtime() - anchorTime) / 1000) + TARGET_DISTANCE_DEVIATION;
|
||||||
|
float distance = MogoApisHandler.getInstance().getApis().getMapServiceApi().getMapUIController().calculateLineDistance(LocationParseUtil.cloudLocationToMogoLatLng(lastLocation), LocationParseUtil.cloudLocationToMogoLatLng(info));
|
||||||
|
Logger.d(TAG,
|
||||||
|
"异常定位点\n准备计算{ lastInfo: " + lastLocation.print() + " info: " + info.print() + " targetDistance: " + targetDistance + " distance : " + distance + "}");
|
||||||
|
// 按照上一个点的方向和速度,计算下一个点的位置,下一个点除坐标点外,其余数据与上一个点相同
|
||||||
|
CloudLocationInfo nextInfo = new CloudLocationInfo(lastLocation);
|
||||||
|
MogoLatLng nextLatLon = computerThatLonLat(lastLocation.getLon(),
|
||||||
|
lastLocation.getLat(), lastLocation.getHeading(), targetDistance);
|
||||||
|
nextInfo.setLon(nextLatLon.lon);
|
||||||
|
nextInfo.setLat(nextLatLon.lat);
|
||||||
|
if(recordLocation()) {
|
||||||
|
errList.add(info);
|
||||||
|
correctList.add(nextInfo);
|
||||||
|
}
|
||||||
|
lastLocation = nextInfo;
|
||||||
|
anchorTime = SystemClock.elapsedRealtime();
|
||||||
|
errCount++;
|
||||||
|
Logger.d(TAG, "异常点纠偏 info: " + lastLocation);
|
||||||
|
if(recordLocation()) {
|
||||||
|
correctList.add(nextInfo);
|
||||||
|
}
|
||||||
|
// return lastLocation;
|
||||||
|
return nextInfo;
|
||||||
|
}catch (Exception e){
|
||||||
|
Logger.e(TAG, e, "纠偏异常");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLocationValid(CloudLocationInfo info) {
|
||||||
|
return info.getLat() != 0 && info.getLon() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RecordLocationListener recordLocationListener = null;
|
||||||
|
private boolean hasCallbackReocrd = false;
|
||||||
|
|
||||||
|
public void setRecordLocationListener(RecordLocationListener recordLocationListener) {
|
||||||
|
this.recordLocationListener = recordLocationListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean recordLocation(){
|
||||||
|
if (historyList.size() >= 100 && !hasCallbackReocrd && recordLocationListener != null) {
|
||||||
|
hasCallbackReocrd = true;
|
||||||
|
recordLocationListener.onRecordFinish(historyList, correctList,validList,correctList);
|
||||||
|
}
|
||||||
|
return historyList.size() < 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据距离和角度计算下一个经纬度
|
||||||
|
* 大地坐标系资料WGS-84 长半径a=6378137 短半径b=6356752.3142 扁率f=1/298.2572236
|
||||||
|
*/
|
||||||
|
public MogoLatLng computerThatLonLat(double lon, double lat, double brng, double dist) {
|
||||||
|
|
||||||
|
double alpha1 = rad(brng);
|
||||||
|
double sinAlpha1 = Math.sin(alpha1);
|
||||||
|
double cosAlpha1 = Math.cos(alpha1);
|
||||||
|
|
||||||
|
// 扁率f=1/298.2572236
|
||||||
|
double f = 1 / 298.2572236;
|
||||||
|
double tanU1 = (1 - f) * Math.tan(rad(lat));
|
||||||
|
double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1));
|
||||||
|
double sinU1 = tanU1 * cosU1;
|
||||||
|
double sigma1 = Math.atan2(tanU1, cosAlpha1);
|
||||||
|
double sinAlpha = cosU1 * sinAlpha1;
|
||||||
|
double cosSqAlpha = 1 - sinAlpha * sinAlpha;
|
||||||
|
// 长半径a=6378137
|
||||||
|
double a = 6378137;
|
||||||
|
// 短半径b=6356752.3142
|
||||||
|
double b = 6356752.3142;
|
||||||
|
double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
|
||||||
|
double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
|
||||||
|
double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
|
||||||
|
|
||||||
|
double cos2SigmaM=0;
|
||||||
|
double sinSigma=0;
|
||||||
|
double cosSigma=0;
|
||||||
|
double sigma = dist / (b * A), sigmaP = 2 * Math.PI;
|
||||||
|
while (Math.abs(sigma - sigmaP) > 1e-12) {
|
||||||
|
cos2SigmaM = Math.cos(2 * sigma1 + sigma);
|
||||||
|
sinSigma = Math.sin(sigma);
|
||||||
|
cosSigma = Math.cos(sigma);
|
||||||
|
double deltaSigma = B * sinSigma * (cos2SigmaM + B / 4 * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)
|
||||||
|
- B / 6 * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma) * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
|
||||||
|
sigmaP = sigma;
|
||||||
|
sigma = dist / (b * A) + deltaSigma;
|
||||||
|
}
|
||||||
|
|
||||||
|
double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
|
||||||
|
double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
|
||||||
|
(1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
|
||||||
|
double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
|
||||||
|
double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
|
||||||
|
double L = lambda - (1 - C) * f * sinAlpha
|
||||||
|
* (sigma + C * sinSigma * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
|
||||||
|
|
||||||
|
// final bearing
|
||||||
|
double revAz = Math.atan2(sinAlpha, -tmp);
|
||||||
|
|
||||||
|
System.out.println(revAz);
|
||||||
|
System.out.println(lon+deg(L)+","+deg(lat2));
|
||||||
|
return new MogoLatLng(deg(lat2), lon + deg(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 度换成弧度
|
||||||
|
*
|
||||||
|
* @param d
|
||||||
|
* 度
|
||||||
|
* @return 弧度
|
||||||
|
*/
|
||||||
|
private double rad(double d) {
|
||||||
|
return d * Math.PI / 180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 弧度换成度
|
||||||
|
*
|
||||||
|
* @param x
|
||||||
|
* 弧度
|
||||||
|
* @return 度
|
||||||
|
*/
|
||||||
|
private double deg(double x) {
|
||||||
|
return x * 180 / Math.PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface RecordLocationListener{
|
||||||
|
void onRecordFinish(List<CloudLocationInfo> history, List<CloudLocationInfo> correct, List<CloudLocationInfo> valid, List<CloudLocationInfo> err);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.mogo.realtime.websocket;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.CloudLocationInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public
|
||||||
|
/**
|
||||||
|
* @author congtaowang
|
||||||
|
* @since 2020/10/25
|
||||||
|
*
|
||||||
|
* 自车定位信息
|
||||||
|
*/
|
||||||
|
class LocationResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sn
|
||||||
|
*/
|
||||||
|
public String sn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后一个定位点的莫顿码
|
||||||
|
*/
|
||||||
|
public long mortonCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最后一个定位点
|
||||||
|
*/
|
||||||
|
public CloudLocationInfo lastCoordinate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1s 内的连续定位点
|
||||||
|
*/
|
||||||
|
public List< CloudLocationInfo > coordinates;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.mogo.realtime.websocket;
|
||||||
|
|
||||||
|
|
||||||
|
import com.mogo.realtime.entity.ADASRecognizedResult;
|
||||||
|
import com.mogo.realtime.location.LocationResult;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public
|
||||||
|
/**
|
||||||
|
* @author congtaowang
|
||||||
|
* @since 2020/10/25
|
||||||
|
*
|
||||||
|
* 一秒一次的上行数据
|
||||||
|
*/
|
||||||
|
class OnePerSecondSendContent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自车定位点
|
||||||
|
*/
|
||||||
|
public LocationResult self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adas 识别物体:1s 识别到的最后帧
|
||||||
|
*/
|
||||||
|
public List<ADASRecognizedResult> adas;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user