Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -27,16 +27,15 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
|
||||
implementation rootProject.ext.dependencies.androidxccorektx
|
||||
implementation rootProject.ext.dependencies.androidxappcompat
|
||||
|
||||
implementation rootProject.ext.dependencies.okhttpinterceptor
|
||||
api rootProject.ext.dependencies.retrofit
|
||||
api rootProject.ext.dependencies.retrofitadapter
|
||||
api rootProject.ext.dependencies.retrofitconvertergson
|
||||
api rootProject.ext.dependencies.retrofitconverterscalars
|
||||
|
||||
implementation project(path: ':foudations:mogo-httpdns')
|
||||
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.WRITE_TIMEOUT
|
||||
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 okhttp3.Dns
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import java.net.InetAddress
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@@ -23,8 +22,7 @@ class OkHttpFactory private constructor() {
|
||||
companion object {
|
||||
val okHttpClient: OkHttpClient by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
OkHttpClient.Builder()
|
||||
.addInterceptor(RequestLogInterceptor())
|
||||
.addInterceptor(ResponseLogInterceptor())
|
||||
.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
|
||||
.addNetworkInterceptor(HeaderNetworkInterceptor())
|
||||
.connectTimeout(CONNECT_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 {
|
||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation project(path: ':foudations:mogo-passport')
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
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