Merge branch 'ad'

This commit is contained in:
liujing
2021-01-21 11:36:01 +08:00
14 changed files with 1244 additions and 1 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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