[6.8.4]
[fea] [add bridge module]
This commit is contained in:
5
OCH/common/bridge/src/main/AndroidManifest.xml
Normal file
5
OCH/common/bridge/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mogo.och.bridge">
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.mogo.och.bridge.autopilot;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotActionsListener;
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatisticsListener;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotActionsListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotStatisticsListenerManager;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerParallelDrivingActionsListenerManager;
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger;
|
||||
import com.mogo.eagle.core.utilcode.util.ParseVersionUtils;
|
||||
import com.mogo.och.bridge.autopilot.callback.OchAdasStartFailureCallback;
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager;
|
||||
import com.zhjt.mogo.adas.data.bean.AutopilotStatistics;
|
||||
import com.zhjt.mogo.adas.data.bean.LaunchConditionData;
|
||||
import com.zhjt.mogo.adas.data.bean.UnableLaunchReason;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import fsm.Fsm2024;
|
||||
|
||||
/**
|
||||
* Created on 2022/10/9
|
||||
* 工控机状态信息回调(判断是否能否启动自动驾驶的回调)
|
||||
* 目前定的是3秒回调一次
|
||||
*/
|
||||
public class OCHAdasAbilityManager implements IMoGoAutopilotActionsListener, IMoGoAutopilotStatisticsListener {
|
||||
|
||||
private static final String TAG = OCHAdasAbilityManager.class.getSimpleName();
|
||||
|
||||
private boolean isAutopilotAbility;
|
||||
private LaunchConditionData launchConditionData;
|
||||
private ArrayList<UnableLaunchReason> unableAutopilotReasons;
|
||||
private String startFailedCode = "";
|
||||
private String startFailedMessage = "";
|
||||
|
||||
private OchAdasStartFailureCallback failureCallback = null;
|
||||
|
||||
private static final class SingletonHolder {
|
||||
private static final OCHAdasAbilityManager INSTANCE = new OCHAdasAbilityManager();
|
||||
}
|
||||
|
||||
public static OCHAdasAbilityManager getInstance() {
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
public void init(Context context) {
|
||||
this.isAutopilotAbility = CallerAutopilotActionsListenerManager.INSTANCE.isAutopilotAbility();
|
||||
this.launchConditionData = CallerAutopilotActionsListenerManager.INSTANCE.getLaunchConditionData();
|
||||
this.unableAutopilotReasons = CallerAutopilotActionsListenerManager.INSTANCE.getUnableAutopilotReasons();
|
||||
initListeners();
|
||||
}
|
||||
|
||||
public void setAdasStartFailureCallback(OchAdasStartFailureCallback callback){
|
||||
failureCallback = callback;
|
||||
}
|
||||
|
||||
public boolean getAutopilotAbilityStatus(){
|
||||
return isAutopilotAbility;
|
||||
}
|
||||
|
||||
public String getAbilityVersion() {
|
||||
return launchConditionData == null ? "" : launchConditionData.abilityVersion;
|
||||
}
|
||||
|
||||
public String getOriginalData() {
|
||||
return launchConditionData == null ? "" : launchConditionData.getJson();
|
||||
}
|
||||
|
||||
public ArrayList<UnableLaunchReason> getUnableAutopilotReasons() {
|
||||
return unableAutopilotReasons;
|
||||
}
|
||||
|
||||
public String getAutopilotUnAbilityReason(){
|
||||
try {
|
||||
if(unableAutopilotReasons==null||unableAutopilotReasons.isEmpty()){
|
||||
return "未知异常";
|
||||
}else {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < unableAutopilotReasons.size(); i++) {
|
||||
stringBuilder.append(unableAutopilotReasons.get(i));
|
||||
if(i<unableAutopilotReasons.size()-1){
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
return "未知异常";
|
||||
}
|
||||
}
|
||||
|
||||
public String getStartFailedCode() {
|
||||
return startFailedCode;
|
||||
}
|
||||
|
||||
public String getStartFailedMessage() {
|
||||
return startFailedMessage;
|
||||
}
|
||||
|
||||
private void initListeners() {
|
||||
//2022.10.9 工控机状态信息回调(判断是否能否启动自动驾驶的回调), 目前定的是3秒回调一次
|
||||
CallerAutopilotActionsListenerManager.INSTANCE.addListener(TAG, this);
|
||||
CallerAutopilotStatisticsListenerManager.INSTANCE.addListener(TAG,this);
|
||||
}
|
||||
|
||||
private void releaseListeners() {
|
||||
CallerAutopilotActionsListenerManager.INSTANCE.removeListener(this);
|
||||
CallerAutopilotStatisticsListenerManager.INSTANCE.removeListener(this);
|
||||
CallerParallelDrivingActionsListenerManager.INSTANCE.removeListener(TAG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutopilotAbility(boolean isAutopilotAbility, @Nullable LaunchConditionData launchConditionData, @Nullable ArrayList<UnableLaunchReason> unableAutopilotReasons) {
|
||||
this.isAutopilotAbility = isAutopilotAbility;
|
||||
this.launchConditionData = launchConditionData;
|
||||
this.unableAutopilotReasons = unableAutopilotReasons;
|
||||
Logger.d(TAG, "是否可以启动自动驾驶=" + isAutopilotAbility + " 原因=" + (unableAutopilotReasons == null ? null : unableAutopilotReasons.toString()) + " 原始数据=" + (launchConditionData == null ? null : launchConditionData.getJson()));
|
||||
if (unableAutopilotReasons != null && getMapVersion() < 30600) {
|
||||
//刹车变化回调
|
||||
Logger.d(TAG,"onAutopilotAbility = " + isAutopilotAbility +
|
||||
" onAutopilotAbility =" + unableAutopilotReasons.toString());
|
||||
if (unableAutopilotReasons.toString().contains(UnableLaunchReason.SourceType.CHASSIS.name())
|
||||
&& unableAutopilotReasons.toString().contains(UnableLaunchReason.UnableType.CHASSIS_BRAKE.name())) {
|
||||
//failureCallback.brakeStatusChanged(isAutopilotAbility);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onAutopilotStatistics(@Nullable AutopilotStatistics statistics) {
|
||||
if (statistics == null) return;
|
||||
Logger.d(TAG, "AutopilotStatistics= " + statistics.status);
|
||||
if (failureCallback != null) {
|
||||
if(statistics.status==1) {
|
||||
if (statistics.fsmState != null) {
|
||||
startFailedCode = "";
|
||||
if (statistics.fsmState.hasSession()) {
|
||||
Fsm2024.Session session = statistics.fsmState.getSession();
|
||||
if (session.hasSessionFailReason()) {
|
||||
startFailedMessage = session.getSessionFailReason();
|
||||
}
|
||||
}
|
||||
} else if (statistics.failedMessage != null) {
|
||||
startFailedCode = statistics.failedMessage.getCode();
|
||||
startFailedMessage = statistics.failedMessage.getMsg();
|
||||
}
|
||||
failureCallback.onStartAutopilotFailure(startFailedCode, startFailedMessage);
|
||||
if (!AppIdentityModeUtils.isSweeper(FunctionBuildConfig.appIdentityMode)) {
|
||||
LineManager.invokeStartAutopilotFailure(startFailedCode, startFailedMessage);
|
||||
}
|
||||
Logger.d(TAG, String.format("statistics-startFailedCode = s%; startFailedMessage = s%",
|
||||
startFailedCode, startFailedMessage));
|
||||
}else if(statistics.status==0) {
|
||||
//启动自驾成功
|
||||
failureCallback.onStartAutopilotSuccess(statistics.source.toString());
|
||||
LineManager.INSTANCE.triggerStartServiceEvent(true, 2,statistics.source.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getMapVersion(){
|
||||
return ParseVersionUtils.parseVersion(true, CallerAutoPilotStatusListenerManager.INSTANCE.getDockerVersion());
|
||||
}
|
||||
public void release() {
|
||||
releaseListeners();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot;
|
||||
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters;
|
||||
import com.mogo.och.bridge.autopilot.autopilot.bean.ArrivedStation;
|
||||
import com.zhjt.mogo.adas.data.AdasConstants;
|
||||
|
||||
import mogo.telematics.pad.MessagePad;
|
||||
import mogo_msg.MogoReportMsg;
|
||||
import system_master.SsmInfo;
|
||||
import system_master.SystemStatusInfo;
|
||||
|
||||
public interface IOchAutopilotStatusListener {
|
||||
/**
|
||||
* 自驾路线触发下载请求回调
|
||||
*/
|
||||
default void onAutopilotTrajectoryDownloadReq(AutopilotControlParameters.AutoPilotLine autoPilotLine, int downloadType) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动驾驶状态信息
|
||||
*
|
||||
* @param state 状态信息
|
||||
*/
|
||||
default void onAutopilotStatusResponse(int state) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动驾驶docker信息
|
||||
*
|
||||
* @param dockerVersion docker版本
|
||||
*/
|
||||
default void onAutopilotDockerInfo(String dockerVersion) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动驾驶到站
|
||||
*
|
||||
* @param arrivalNotification 所到车站的简单信息
|
||||
*/
|
||||
default void onAutopilotArriveAtStation(ArrivedStation arrivalNotification) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 工控机获取SN
|
||||
*/
|
||||
default void onAutopilotSNRequest(MessagePad.BasicInfoReq basicInfoReq) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 监控事件报告
|
||||
*/
|
||||
default void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 监控事件报告
|
||||
*/
|
||||
default void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo, long lineId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 工控机连接状态回调
|
||||
*/
|
||||
default void onAutopilotIpcConnectStatusChanged(AdasConstants.IpcConnectionStatus status, String reason) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 工控机主动查询 AdasManager#sendStatusQueryReq(),后会收到如下回调
|
||||
*/
|
||||
default void onAutopilotStatusRespByQuery(SystemStatusInfo.StatusInfo status) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 定频SSM
|
||||
* 老版本 SSM(SystemStatusInfo.StatusInfo) HQ、M1 MAP350开始弃用,其他车型MAP360开始弃用
|
||||
*/
|
||||
default void onSystemStatus(SsmInfo.SsmStatusInf statusInf) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动驾驶路线ID回调
|
||||
*/
|
||||
default void onAutopilotRouteLineId(long lineId) {
|
||||
}
|
||||
/**
|
||||
* 自动驾驶路线ID回调
|
||||
*/
|
||||
default void canStartAutopilot(boolean canStart) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动驾驶状态信息 数据源来自底盘 不管是否存在FSM 都将进行底盘自驾状态的转发
|
||||
*
|
||||
* @param state 状态信息
|
||||
*/
|
||||
default void onAutopilotStatusResponseFromCan(int state) {}
|
||||
|
||||
default void onFsmCanStartAutopilot(boolean can){}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot;
|
||||
|
||||
public interface IOchEventKey {
|
||||
// 无人化taxi event_key_unmanned_taxi_start_service *
|
||||
// bus event_key_och_bus_start_service *
|
||||
// shuttle event_key_och_bus_start_service *
|
||||
// charter event_key_och_charter_start_service
|
||||
// taxi event_key_och_taxi_start_service *
|
||||
// 无人化taxiPa event_key_unmanned_taxi_start_service
|
||||
String getEventKeyStartService();
|
||||
|
||||
// 无人化taxi event_key_unmanned_taxi_restart_autopilot *
|
||||
// bus event_key_och_bus_restart_autopilot *
|
||||
// shuttle event_key_och_bus_restart_autopilot *
|
||||
// charter event_key_och_charter_restart_autopilot
|
||||
// taxi event_key_och_taxi_restart_autopilot *
|
||||
// 无人化taxiPa event_key_unmanned_taxi_restart_autopilot
|
||||
String getEventKeyRestartService();
|
||||
|
||||
// 无人化taxi event_key_och_taxi_ap_unable_start_reason *
|
||||
// bus event_key_och_bus_ap_unable_start_reason *
|
||||
// shuttle event_key_och_bus_ap_unable_start_reason *
|
||||
// charter event_key_och_charter_ap_unable_start_reason
|
||||
// taxi event_key_och_taxi_ap_unable_start_reason *
|
||||
// 无人化taxiPa event_key_och_taxi_ap_unable_start_reason
|
||||
String getEventKeyApUnableStartReason();
|
||||
|
||||
// 无人化taxi event_key_unmanned_taxi_click_start_autopilot
|
||||
// bus event_key_och_bus_click_start_autopilot
|
||||
// shuttle event_key_och_bus_click_start_autopilot
|
||||
// charter event_key_och_charter_click_start_autopilot
|
||||
// taxi event_key_och_taxi_click_start_autopilot
|
||||
// 无人化taxiPa event_key_och_taxi_passenger_click_start_autopilot
|
||||
String getEventKeyClickStartAutopilot();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot
|
||||
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.data.msgbox.AutopilotMsg
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxBean
|
||||
import com.mogo.eagle.core.data.msgbox.MsgBoxType
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.msgbox.CallerMsgBoxManager
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.bridge.autopilot.OCHAdasAbilityManager
|
||||
import com.mogo.och.bridge.autopilot.autopilot.bean.SessionWithTime
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
import com.mogo.och.bridge.distance.TrajectoryAndDistanceManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
object OchAutoPilotManager {
|
||||
|
||||
const val TAG = "OchAutoPilotManager"
|
||||
|
||||
private val globalSessionId = AtomicReference<SessionWithTime>()
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun canStartAutoPilotByDistance(lineId: Number?): String {
|
||||
return TrajectoryAndDistanceManager.canStartAutopilot(lineId).apply {
|
||||
if (!isNullOrBlank()) {
|
||||
// 去启动绘制高精地图上的轨迹
|
||||
val drawGlobalTrajectory = LineManager.drawGlobalTrajectory()
|
||||
if (!drawGlobalTrajectory.first) {
|
||||
ToastUtils.showLong(drawGlobalTrajectory.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动自驾中禁止再次启动自驾
|
||||
*/
|
||||
@JvmStatic
|
||||
fun canStartAutopilotBySessionId(): Boolean {
|
||||
val sessionInfo = globalSessionId.get()
|
||||
val currentTimeMillis = System.currentTimeMillis()
|
||||
if(sessionInfo==null){
|
||||
return true
|
||||
}else{
|
||||
if(currentTimeMillis-sessionInfo.setTime>= OchAutopilotAnalytics.LOOP_PERIOD_16S){
|
||||
clearGlobalSessionId("检测session 自带的时间 ${currentTimeMillis}_${sessionInfo.setTime}_${sessionInfo.sessionId}")
|
||||
return true
|
||||
}else{
|
||||
ToastUtils.showLong("自驾启动中,请勿重复点击")
|
||||
OchAutopilotAnalytics.triggerCanStartAutopilotBySessionId(globalSessionId.get())
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun canStartAutopilotBySessionIdInner():Boolean{
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","清理SessiongId")
|
||||
return (globalSessionId.get()==null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun canStartAutoPilotSSM(): Boolean {
|
||||
if (!FunctionBuildConfig.isDemoMode && !OCHAdasAbilityManager.getInstance().autopilotAbilityStatus) {
|
||||
val reasons = OCHAdasAbilityManager.getInstance().unableAutopilotReasons
|
||||
if ("AutopilotAbilityFSM" == OCHAdasAbilityManager.getInstance().abilityVersion && !reasons.isNullOrEmpty()) {
|
||||
val msg = reasons[0].getUnableLaunchReason() + " 来源:" + reasons[0].source
|
||||
CallerMsgBoxManager.saveMsgBox(
|
||||
MsgBoxBean(
|
||||
MsgBoxType.AUTOPILOT,
|
||||
AutopilotMsg(0, "自动驾驶启动失败", msg, System.currentTimeMillis())
|
||||
)
|
||||
)
|
||||
} else {
|
||||
ToastUtils.showLong(
|
||||
OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason +
|
||||
", 请稍候重试"
|
||||
)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun clearGlobalSessionId(log:String){
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","清理SessiongId${globalSessionId}_${OchAutoPilotStatusListenerManager.fsmBackSessionId}_${log}")
|
||||
globalSessionId.set(null)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun startAutoPilot(controlParameters: AutopilotControlParameters?): Long {
|
||||
val sessionId = CallerAutoPilotControlManager.startAutoPilot(controlParameters)
|
||||
globalSessionId.set(SessionWithTime(sessionId,System.currentTimeMillis()))
|
||||
OchAutoPilotStatusListenerManager.fsmBackSessionId.set(-1L)
|
||||
OchAutopilotAnalytics.triggerStartAutopilotParameters(controlParameters, sessionId)
|
||||
return sessionId
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动自驾失败切 FSM返回的Session和启动SessionId 不同
|
||||
*/
|
||||
fun checkStartSessionAndFailSessionId(){
|
||||
val sessionInfo = globalSessionId.get()
|
||||
if(sessionInfo!=null) {
|
||||
if (sessionInfo.sessionId != OchAutoPilotStatusListenerManager.fsmBackSessionId.get()) {
|
||||
OchAutopilotAnalytics.triggerStartAutopilotFailCheckSessionDiff(
|
||||
sessionInfo,
|
||||
OchAutoPilotStatusListenerManager.fsmBackSessionId.get()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot
|
||||
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoFsm2024Listener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoReceiveReceivedAckListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerFsm2024ListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerReceiveReceivedAckListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.util.StringUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.bridge.autopilot.autopilot.bean.ArrivedStation
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
import com.mogo.och.bridge.autopilot.trajectory.TrajectoryManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.utils.CallerBase
|
||||
import com.zhjt.mogo.adas.common.MessageType
|
||||
import com.zhjt.mogo.adas.data.AdasConstants
|
||||
import com.zhjt.mogo.adas.data.bean.ReceivedAck
|
||||
import com.zhjt.mogo.adas.data.bean.ReceivedAck.Status
|
||||
import fsm.Fsm2024
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import mogo_msg.MogoReportMsg
|
||||
import system_master.SsmInfo
|
||||
import system_master.SystemStatusInfo
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
object OchAutoPilotStatusListenerManager : CallerBase<IOchAutopilotStatusListener>(),IMoGoAutopilotStatusListener,
|
||||
(Boolean) -> Unit, IMoGoFsm2024Listener, IMoGoReceiveReceivedAckListener {
|
||||
|
||||
const val TAG = "OCHAutoPilotStatusListenerManager"
|
||||
|
||||
val fsmBackSessionId = AtomicLong(-1L)
|
||||
|
||||
private var canStartAutopilot:Boolean? by Delegates.observable(null) { _, oldValue, newValue ->
|
||||
if (oldValue != newValue) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.canStartAutopilot(newValue?:false)
|
||||
}
|
||||
}
|
||||
}
|
||||
private var _canStartAutopilotFromFSM:Boolean by Delegates.observable(true) { _, oldValue, newValue ->
|
||||
if (oldValue != newValue) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onFsmCanStartAutopilot(newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val canStartAutopilotFromFSM:Boolean
|
||||
get() = _canStartAutopilotFromFSM
|
||||
|
||||
private var _autopilotState: Int by Delegates.observable(0) { _, oldValue, newValue ->
|
||||
if (oldValue != newValue) {
|
||||
if (AppIdentityModeUtils.isDriver(FunctionBuildConfig.appIdentityMode)) {
|
||||
if(oldValue==IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){
|
||||
if(newValue==IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE){
|
||||
ToastUtils.showLong(R.string.common_change2_autopilot2_manual)
|
||||
}
|
||||
}else if(oldValue==IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING){
|
||||
if(newValue==IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE){
|
||||
ToastUtils.showLong(R.string.common_change2_pxjs_manual)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(newValue==IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
|
||||
LineManager.triggerStartServiceEvent(true, 0,"")
|
||||
}
|
||||
|
||||
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotStatusResponse(newValue)
|
||||
}
|
||||
LineManager.searchAutopilotState()
|
||||
}
|
||||
}
|
||||
val autopilotState:Int
|
||||
get() = _autopilotState
|
||||
init {
|
||||
//2021.11.1 鹰眼架构整合,由IMoGoAutopilotStatusListener逐步替代IMogoAdasOCHCallback接口
|
||||
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||
CallerAutoPilotControlManager.addStartAutopilotStateListener(TAG,this)
|
||||
CallerFsm2024ListenerManager.addListener(TAG,this)
|
||||
CallerReceiveReceivedAckListenerManager.addListener(TAG,this)
|
||||
}
|
||||
|
||||
override fun doSomeAfterAddListener(tag: String, listener: IOchAutopilotStatusListener) {
|
||||
super.doSomeAfterAddListener(tag, listener)
|
||||
listener.onAutopilotStatusResponse(_autopilotState)
|
||||
}
|
||||
|
||||
override fun onAutopilotTrajectoryDownloadReq(
|
||||
autoPilotLine: AutopilotControlParameters.AutoPilotLine,
|
||||
downloadType: Int
|
||||
) {
|
||||
super.onAutopilotTrajectoryDownloadReq(autoPilotLine, downloadType)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotTrajectoryDownloadReq(autoPilotLine,downloadType)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotStatusResponse(state: Int) {
|
||||
_autopilotState = state
|
||||
}
|
||||
|
||||
override fun onAutopilotDockerInfo(dockerVersion: String) {
|
||||
super.onAutopilotDockerInfo(dockerVersion)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotDockerInfo(dockerVersion)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotSNRequest(basicInfoReq: MessagePad.BasicInfoReq) {
|
||||
super.onAutopilotSNRequest(basicInfoReq)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotSNRequest(basicInfoReq)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) {
|
||||
super.onAutopilotGuardian(guardianInfo)
|
||||
var lineId = -1L
|
||||
guardianInfo?.let {
|
||||
val msg = guardianInfo.msg
|
||||
try {
|
||||
val regex = Regex("lineid:(\\d+)")
|
||||
val matchResult = regex.find(msg)
|
||||
if (matchResult != null) {
|
||||
lineId = matchResult.groupValues[1].toLong()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
if (lineId == -1L) {
|
||||
try {
|
||||
val regex = Regex("lineID=(\\d+)")
|
||||
val matchResult = regex.find(msg)
|
||||
if (matchResult != null) {
|
||||
lineId = matchResult.groupValues[1].toLong()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrajectoryManager.carDownLoadTrajectoryLog(guardianInfo?.code,lineId)
|
||||
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotGuardian(guardianInfo)
|
||||
listener.onAutopilotGuardian(guardianInfo, lineId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotIpcConnectStatusChanged(
|
||||
status: AdasConstants.IpcConnectionStatus,
|
||||
reason: String?
|
||||
) {
|
||||
super.onAutopilotIpcConnectStatusChanged(status, reason)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotIpcConnectStatusChanged(status,reason)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotStatusRespByQuery(status: SystemStatusInfo.StatusInfo) {
|
||||
super.onAutopilotStatusRespByQuery(status)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotStatusRespByQuery(status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSystemStatus(statusInf: SsmInfo.SsmStatusInf) {
|
||||
super.onSystemStatus(statusInf)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onSystemStatus(statusInf)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotRouteLineId(lineId: Long) {
|
||||
super.onAutopilotRouteLineId(lineId)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotRouteLineId(lineId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun invoke(canStartAutopilot: Boolean) {
|
||||
OchAutoPilotStatusListenerManager.canStartAutopilot = canStartAutopilot
|
||||
}
|
||||
|
||||
override fun onAutopilotStatusResponseFromCan(state: Int) {
|
||||
super.onAutopilotStatusResponseFromCan(state)
|
||||
LineManager.searchAutopilotState()
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotStatusResponseFromCan(state)
|
||||
}
|
||||
when (state) {
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING -> {
|
||||
LineManager.triggerStartServiceEvent(true,1,"")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotArriveAtStation(arrivalNotification: MessagePad.ArrivalNotification?) {
|
||||
super.onAutopilotArriveAtStation(arrivalNotification)
|
||||
val trasform = ArrivedStation.trasform(arrivalNotification)
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.onAutopilotArriveAtStation(trasform)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutoPilotStation(
|
||||
token: Long,
|
||||
timestamp: Long,
|
||||
autoPilotStation: SsmInfo.AutoPilotStation?
|
||||
) {
|
||||
OchChainLogManager.writeChainLogAutopilot("到站逻辑",
|
||||
"token:$token 通过主动查询到站底盘传递:${autoPilotStation?.orderId}_${autoPilotStation?.arrivedStationFlag}")
|
||||
autoPilotStation?.let {
|
||||
if (it.hasOrderId() && !StringUtils.isEmpty(it.orderId)&&it.hasArrivedStationFlag()) {
|
||||
LineManager.invokeArrivedStation(it.orderId,it.arrivedStationFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun onAutoPilotInfo(token: Long, timestamp: Long, autoPilotInfo: SsmInfo.AutoPilotInfo?) {
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾状态",
|
||||
"token:$token 通过主动查询到站底盘传递:${autoPilotInfo?.orderId}_第一次启动自驾${autoPilotInfo?.firstAutopilotFlag}_次数:${autoPilotInfo?.count}")
|
||||
autoPilotInfo?.let {
|
||||
if (it.hasOrderId() && !StringUtils.isEmpty(it.orderId)) {
|
||||
LineManager.invokeSetIsFirstAutopilot(it.orderId,it.firstAutopilotFlag,it.count)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFSM2024State(fsmState: Fsm2024.FSMStateMsg) {
|
||||
fsmBackSessionId.set(fsmState.failToPilotSessionId)
|
||||
_canStartAutopilotFromFSM = fsmState.pilotStandbyFlag
|
||||
}
|
||||
|
||||
override fun onReceiveReceivedAck(receivedAck: ReceivedAck) {
|
||||
if (receivedAck.messageType == MessageType.TYPE_SEND_SET_AUTOPILOT_MODE_REQ) {
|
||||
OchAutopilotAnalytics.triggerStartAutopilotParametersAck(
|
||||
receivedAck.toString(),
|
||||
receivedAck.status == Status.NORMAL
|
||||
)
|
||||
if(receivedAck.status==Status.NORMAL){
|
||||
// 底盘接受成功
|
||||
LineManager.invokeStartAutopilotAckSuccess(receivedAck)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.mogo.commons.debug.DebugConfig
|
||||
import com.mogo.commons.utils.MogoAnalyticUtils
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.DateTimeUtils
|
||||
import com.mogo.och.bridge.autopilot.OCHAdasAbilityManager
|
||||
import com.mogo.och.bridge.autopilot.autopilot.bean.SessionWithTime
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
import com.mogo.och.common.module.exception.InitException
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
object OchAutopilotAnalytics {
|
||||
|
||||
private const val EVENT_PARAM_AUTOPILOTANALYTICS_GROUP = "start_autopilot_group"
|
||||
private const val EVENT_PARAM_ENV_ONLINE = "env_online" // 是否线上环境:true/false
|
||||
private const val EVENT_PARAM_START_SUCCESS_TIME = "time_success"
|
||||
private const val EVENT_PARAM_START_FAIL_TIME = "time_fail"
|
||||
private const val EVENT_PARAM_CLICK_TIME = "time_click"
|
||||
private const val EVENT_PARAM_START_NAME = "start_name"
|
||||
private const val EVENT_PARAM_END_NAME = "end_name"
|
||||
private const val EVENT_PARAM_LINE_ID = "line_id"
|
||||
private const val EVENT_PARAM_ORDER_NUMBER = "order_num"
|
||||
private const val EVENT_PARAM_AUTOPILOT_FROM = "AUTOPILOT_FROM"
|
||||
private const val EVENT_PARAM_UNABLE_START_REASON = "unable_start_reason"
|
||||
private const val EVENT_PARAM_MAP_ORIGINAL_DATA = "map_original_data" // 域控原始状态信息
|
||||
private const val EVENT_PARAM_AUTOPILOT_STATE = "autopilot_state" //原始的自动驾驶状态
|
||||
private const val EVENT_PARAM_START_RESULT = "start_autopilot" // true/false
|
||||
private const val EVENT_PARAM_START_RESULT_SOURCE = "start_autopilot_source" // true/false
|
||||
private const val EVENT_PARAM_START_FAILURE_CODE = "start_autopilot_failure_code" // 启动自驾失败code
|
||||
private const val EVENT_PARAM_START_FAILURE_MSG = "start_autopilot_failure_msg" // 启动自驾失败原因
|
||||
private const val EVENT_PARAM_START_AUTOPILOT_SESSION_ID = "start_autopilot_cmd_session_id" //启动自驾命令请求的sessionId
|
||||
|
||||
private const val EVENT_KEY_START_AUTOPILOT_PARAMETERS = "event_key_och_start_autopilot_parameters"
|
||||
private const val EVENT_PARAM_START_AUTOPILOT_PARAMETERS= "start_autopilot_parameters" // 启动自驾参数
|
||||
|
||||
private const val EVENT_KEY_START_AUTOPILOT_ACK = "event_key_och_start_autopilot_ack"
|
||||
private const val EVENT_PARAM_START_AUTOPILOT_ACK= "start_autopilot_parameters_ack" // 启动自驾参数
|
||||
private const val EVENT_PARAM_START_AUTOPILOT_ACK_SUCCESS= "start_autopilot_parameters_ack_isSuccess" // 启动自驾参数
|
||||
|
||||
private const val EVENT_KEY_INFO_AUTOPILOT_DISTANCE = "event_key_vehicle_start_autopilot_state_distance_15"
|
||||
|
||||
private const val EVENT_KEY_VEHICLE_START_AUTOPILOT_CMD_SESSION_DUPLICATED = "event_key_vehicle_start_autopilot_cmd_session_duplicated"
|
||||
private const val EVENT_KEY_VEHICLE_START_AUTOPILOT_CMD_SESSION_DIFF = "event_key_vehicle_start_autopilot_cmd_session_diff"
|
||||
private const val EVENT_PARAM_VEHICLE_START_AUTOPILOT_CMD_SESSION_ID_START = "cmd_session_id_start"
|
||||
private const val EVENT_PARAM_VEHICLE_START_AUTOPILOT_CMD_SESSION_ID_FSM_RETURN = "cmd_session_id_fsm_return"
|
||||
|
||||
private val LOOP_PERIOD_15S = 15 * 1000L
|
||||
val LOOP_PERIOD_16S = 16 * 1000L
|
||||
|
||||
|
||||
private var mStartAutopilotKey: String? = null
|
||||
private val mStartAutopilotParams = HashMap<String, Any>()
|
||||
|
||||
var ochEventKey: IOchEventKey? = null
|
||||
|
||||
|
||||
/**
|
||||
* 正式启动自驾把参数传给底层
|
||||
*/
|
||||
fun triggerStartAutopilotParameters(controlParameters: AutopilotControlParameters?, sessionId: Long){
|
||||
val params = HashMap<String, Any>()
|
||||
params[EVENT_PARAM_ENV_ONLINE] = DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE
|
||||
params[EVENT_PARAM_START_AUTOPILOT_SESSION_ID] = sessionId
|
||||
params[EVENT_PARAM_START_AUTOPILOT_PARAMETERS] = "${controlParameters.toString()}_${controlParameters?.autoPilotLine}_routeID:${controlParameters?.routeID}_routeName:${controlParameters?.routeName}"
|
||||
params[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(params)
|
||||
MogoAnalyticUtils.track(EVENT_KEY_START_AUTOPILOT_PARAMETERS, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 底盘收到启动自驾的ack
|
||||
*/
|
||||
fun triggerStartAutopilotParametersAck(data:String,isSuccess:Boolean){
|
||||
val params = HashMap<String, Any>()
|
||||
params[EVENT_PARAM_ENV_ONLINE] = DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE
|
||||
params[EVENT_PARAM_START_AUTOPILOT_ACK] = data
|
||||
params[EVENT_PARAM_START_AUTOPILOT_ACK_SUCCESS] = isSuccess
|
||||
params[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(params)
|
||||
MogoAnalyticUtils.track(EVENT_KEY_START_AUTOPILOT_ACK, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动自驾判断距离
|
||||
*/
|
||||
fun triggerDistance2LineorStation(info: String){
|
||||
val map = hashMapOf<String, Any>()
|
||||
map[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.writeChainLog("启动自驾距离判断",info, eventID = EVENT_KEY_INFO_AUTOPILOT_DISTANCE, patch = map)
|
||||
}
|
||||
/**
|
||||
* 等待底盘返回的间隙 重复启动自驾
|
||||
*/
|
||||
fun triggerCanStartAutopilotBySessionId(globalSessionId : SessionWithTime){
|
||||
val map = hashMapOf<String, Any>()
|
||||
map[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.writeChainLog("启动自驾Session判断","已有globalSessionId:${globalSessionId.sessionId}_创建时间:${globalSessionId.setTime}", eventID = EVENT_KEY_VEHICLE_START_AUTOPILOT_CMD_SESSION_DUPLICATED, patch = map)
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动失败后 对比两个session是否相同
|
||||
*/
|
||||
fun triggerStartAutopilotFailCheckSessionDiff(globalSessionId: SessionWithTime, fsmBackSessionId: Long){
|
||||
val map = hashMapOf<String, Any>()
|
||||
map[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
map[EVENT_PARAM_VEHICLE_START_AUTOPILOT_CMD_SESSION_ID_START] = "${globalSessionId.sessionId}_${globalSessionId.setTime}"
|
||||
map[EVENT_PARAM_VEHICLE_START_AUTOPILOT_CMD_SESSION_ID_FSM_RETURN] = fsmBackSessionId
|
||||
OchChainLogManager.writeChainLog("启动自驾失败且SessionId不同","globalSessionId:${globalSessionId}——————fsmBackSessionId:${fsmBackSessionId}", eventID = EVENT_KEY_VEHICLE_START_AUTOPILOT_CMD_SESSION_DIFF, patch = map)
|
||||
}
|
||||
|
||||
private var timeOutDisposable: Disposable?=null
|
||||
|
||||
/**
|
||||
* 底盘明确告知启动自驾失败
|
||||
*/
|
||||
fun triggerStartAutopilotFailureEventByAdas(failCode: String, failMsg: String, startFailDate: Long) {
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","启动自驾失败回调${failCode}_${failMsg}")
|
||||
if(OchAutoPilotManager.canStartAutopilotBySessionIdInner()){
|
||||
CallerLogger.e(SceneConstant.M_OCHCOMMON + "triggerStartAutopilotFailureEvent canStartAutopilotBySessionIdInner == false")
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","异常情况 启动自驾失败回调${failCode}_${failMsg}_sessiong为空")
|
||||
return
|
||||
}
|
||||
RxUtils.disposeSubscribe(timeOutDisposable)
|
||||
// 判断Session 是否相同
|
||||
OchAutoPilotManager.checkStartSessionAndFailSessionId()
|
||||
triggerStartAutopilotFailureEvent(failCode, failMsg, startFailDate)
|
||||
}
|
||||
|
||||
private fun clearStartAutopilotParams() {
|
||||
mStartAutopilotParams.clear()
|
||||
}
|
||||
|
||||
private fun triggerStartAutopilotFailureEvent(failCode: String, failMsg: String, startFailDate: Long) {
|
||||
OchAutoPilotManager.clearGlobalSessionId("$failMsg _ ${failCode}")
|
||||
if (mStartAutopilotParams.isEmpty()) {
|
||||
return
|
||||
}
|
||||
CallerLogger.e(SceneConstant.M_OCHCOMMON + "triggerStartAutopilotFailureEvent", failMsg)
|
||||
if (CallerAutoPilotStatusListenerManager.getState() != IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING) {
|
||||
mStartAutopilotParams[EVENT_PARAM_START_FAILURE_CODE] = failCode
|
||||
mStartAutopilotParams[EVENT_PARAM_START_FAILURE_MSG] = failMsg
|
||||
}
|
||||
|
||||
mStartAutopilotParams[EVENT_PARAM_MAP_ORIGINAL_DATA] = OCHAdasAbilityManager.getInstance().originalData
|
||||
mStartAutopilotParams[EVENT_PARAM_AUTOPILOT_STATE] = CallerAutoPilotStatusListenerManager.getState()
|
||||
mStartAutopilotParams[EVENT_PARAM_START_FAIL_TIME] = DateTimeUtils.getTimeText(startFailDate,DateTimeUtils.yyyy_MM_dd_HH_mm_ss_SSS)
|
||||
mStartAutopilotParams[EVENT_PARAM_START_RESULT] = CallerAutoPilotStatusListenerManager.getState() == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING
|
||||
mStartAutopilotParams[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(mStartAutopilotParams)
|
||||
MogoAnalyticUtils.track(mStartAutopilotKey, mStartAutopilotParams)
|
||||
clearStartAutopilotParams() //清空参数数据,防止误传
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发'开启自动驾驶'埋点流程
|
||||
* 开启自动驾驶,15s内成功则发送成功埋点,否则发送失败埋点
|
||||
* @param restart false(点击'滑动出发'启动)/true(接管后点击'自动驾驶'按钮启动)
|
||||
* @param send 是否直接发送埋点(15s内开启成功则直接发送成功埋点)
|
||||
*/
|
||||
fun triggerStartAutopilotEvent(
|
||||
restart: Boolean,
|
||||
send: Boolean,
|
||||
startName: String,
|
||||
endName: String,
|
||||
lineId: Int,
|
||||
orderId:String?,
|
||||
triggerDate: Long,
|
||||
type:String? = "",
|
||||
source:Int = 0
|
||||
) {
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","send:${send}_${restart}_${startName}_${endName}_${lineId}_${orderId}_${source}_${triggerDate}")
|
||||
mStartAutopilotKey = if (restart) getEventKeyRestartService() else getEventKeyStartService()
|
||||
if (send) {
|
||||
if(OchAutoPilotManager.canStartAutopilotBySessionIdInner()){
|
||||
CallerLogger.e(SceneConstant.M_OCHCOMMON + "triggerStartAutopilotEvent canStartAutopilotBySessionIdInner == false")
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾流程","异常情况 启动自驾成功_sessiong为空")
|
||||
return
|
||||
}
|
||||
OchAutoPilotManager.clearGlobalSessionId("启动自驾成功")
|
||||
RxUtils.disposeSubscribe(timeOutDisposable)
|
||||
if (mStartAutopilotParams.isEmpty()) {
|
||||
return
|
||||
}
|
||||
// 开启成功,上报埋点
|
||||
mStartAutopilotParams[EVENT_PARAM_START_FAILURE_CODE] = ""
|
||||
mStartAutopilotParams[EVENT_PARAM_START_FAILURE_MSG] = ""
|
||||
mStartAutopilotParams[EVENT_PARAM_START_RESULT] = true
|
||||
mStartAutopilotParams[EVENT_PARAM_AUTOPILOT_FROM] = type?:""
|
||||
mStartAutopilotParams[EVENT_PARAM_START_RESULT_SOURCE] = source
|
||||
// 自动驾驶状态变更时间
|
||||
mStartAutopilotParams[EVENT_PARAM_START_SUCCESS_TIME] = DateTimeUtils.getTimeText(triggerDate,DateTimeUtils.yyyy_MM_dd_HH_mm_ss_SSS)
|
||||
mStartAutopilotParams[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(mStartAutopilotParams)
|
||||
MogoAnalyticUtils.track(mStartAutopilotKey, mStartAutopilotParams)
|
||||
clearStartAutopilotParams() //清空参数数据,防止误传
|
||||
} else {
|
||||
mStartAutopilotParams[EVENT_PARAM_ENV_ONLINE] = DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE
|
||||
// 外部点击时间
|
||||
mStartAutopilotParams[EVENT_PARAM_CLICK_TIME] = DateTimeUtils.getTimeText(triggerDate,DateTimeUtils.yyyy_MM_dd_HH_mm_ss_SSS)
|
||||
mStartAutopilotParams[EVENT_PARAM_START_NAME] = startName
|
||||
mStartAutopilotParams[EVENT_PARAM_END_NAME] = endName
|
||||
mStartAutopilotParams[EVENT_PARAM_LINE_ID] = lineId
|
||||
mStartAutopilotParams[EVENT_PARAM_ORDER_NUMBER] = orderId?:""
|
||||
RxUtils.disposeSubscribe(timeOutDisposable)
|
||||
timeOutDisposable = RxUtils.createSubscribe(LOOP_PERIOD_15S) {
|
||||
triggerStartAutopilotFailureEvent("", "15s后app等待超时", System.currentTimeMillis())
|
||||
LineManager.invokeStartAutopilotTimeOut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发更新 启动自驾命令 发送的sessionId
|
||||
*/
|
||||
fun triggerUpdateStartAutoPilotSessionId(sessionId: Long) {
|
||||
if (TextUtils.isEmpty(mStartAutopilotKey)) {
|
||||
CallerLogger.e(SceneConstant.M_OCHCOMMON + "triggerUpdateStartAutoPilotSessionId but mStartAutopilotKey is null [sessionId = $sessionId] ")
|
||||
return
|
||||
}
|
||||
if (mStartAutopilotParams.isEmpty()) {
|
||||
CallerLogger.e(SceneConstant.M_OCHCOMMON + "triggerUpdateStartAutoPilotSessionId but mStartAutopilotParams is Empty [sessionId = $sessionId] ")
|
||||
return
|
||||
}
|
||||
mStartAutopilotParams[EVENT_PARAM_START_AUTOPILOT_SESSION_ID] = sessionId
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发"无法开启自驾已知异常"埋点
|
||||
* @param startName
|
||||
* @param endName
|
||||
* @param lineId
|
||||
*/
|
||||
fun triggerUnableStartAPReasonEvent(
|
||||
startName: String, endName: String, lineId: String, orderNo:String ,reason: String
|
||||
) {
|
||||
val params = HashMap<String, Any>()
|
||||
params[EVENT_PARAM_ENV_ONLINE] = DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE
|
||||
params[EVENT_PARAM_START_NAME] = startName
|
||||
params[EVENT_PARAM_END_NAME] = endName
|
||||
params[EVENT_PARAM_LINE_ID] = lineId
|
||||
params[EVENT_PARAM_ORDER_NUMBER] = orderNo
|
||||
params[EVENT_PARAM_UNABLE_START_REASON] = reason
|
||||
params[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(mStartAutopilotParams)
|
||||
MogoAnalyticUtils.track(getEventKeyApUnableStartReason(), params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户点击启动自驾的时间
|
||||
*/
|
||||
fun triggerClickStartAutopilotTime(triggerDate: Long) {
|
||||
val params = HashMap<String, Any>()
|
||||
params[EVENT_PARAM_ENV_ONLINE] = DebugConfig.getNetMode() == DebugConfig.NET_MODE_RELEASE
|
||||
params[EVENT_PARAM_CLICK_TIME] = DateTimeUtils.getTimeText(triggerDate,DateTimeUtils.yyyy_MM_dd_HH_mm_ss_SSS)
|
||||
params[EVENT_PARAM_AUTOPILOTANALYTICS_GROUP] = EVENT_PARAM_AUTOPILOTANALYTICS_GROUP
|
||||
OchChainLogManager.addCommonParams(mStartAutopilotParams)
|
||||
MogoAnalyticUtils.track(getEventKeyClickStartAutopilot(), params)
|
||||
}
|
||||
|
||||
// 无人化taxi event_key_unmanned_taxi_start_service *
|
||||
// bus event_key_och_bus_start_service *
|
||||
// shuttle event_key_och_bus_start_service *
|
||||
// charter event_key_och_charter_start_service
|
||||
// taxi event_key_och_taxi_start_service *
|
||||
// 无人化taxiPa event_key_unmanned_taxi_start_service
|
||||
fun getEventKeyStartService(): String{
|
||||
if(ochEventKey ==null){
|
||||
throw InitException("请设置启动自驾埋点key")
|
||||
}
|
||||
return ochEventKey!!.getEventKeyStartService()
|
||||
}
|
||||
|
||||
// 无人化taxi event_key_unmanned_taxi_restart_autopilot *
|
||||
// bus event_key_och_bus_restart_autopilot *
|
||||
// shuttle event_key_och_bus_restart_autopilot *
|
||||
// charter event_key_och_charter_restart_autopilot
|
||||
// taxi event_key_och_taxi_restart_autopilot *
|
||||
// 无人化taxiPa event_key_unmanned_taxi_restart_autopilot
|
||||
fun getEventKeyRestartService(): String{
|
||||
if(ochEventKey ==null){
|
||||
throw InitException("请设置启动自驾埋点key")
|
||||
}
|
||||
return ochEventKey!!.getEventKeyRestartService()
|
||||
}
|
||||
|
||||
// 无人化taxi event_key_och_taxi_ap_unable_start_reason *
|
||||
// bus event_key_och_bus_ap_unable_start_reason *
|
||||
// shuttle event_key_och_bus_ap_unable_start_reason *
|
||||
// charter event_key_och_charter_ap_unable_start_reason
|
||||
// taxi event_key_och_taxi_ap_unable_start_reason *
|
||||
// 无人化taxiPa event_key_och_taxi_ap_unable_start_reason
|
||||
fun getEventKeyApUnableStartReason(): String{
|
||||
if(ochEventKey ==null){
|
||||
throw InitException("请设置启动自驾埋点key")
|
||||
}
|
||||
return ochEventKey!!.getEventKeyApUnableStartReason()
|
||||
}
|
||||
|
||||
// 无人化taxi event_key_unmanned_taxi_click_start_autopilot
|
||||
// bus event_key_och_bus_click_start_autopilot
|
||||
// shuttle event_key_och_bus_click_start_autopilot
|
||||
// charter event_key_och_charter_click_start_autopilot
|
||||
// taxi event_key_och_taxi_click_start_autopilot
|
||||
// 无人化taxiPa event_key_och_taxi_passenger_click_start_autopilot
|
||||
fun getEventKeyClickStartAutopilot(): String{
|
||||
if(ochEventKey ==null){
|
||||
throw InitException("请设置启动自驾埋点key")
|
||||
}
|
||||
return ochEventKey!!.getEventKeyClickStartAutopilot()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot.bean;
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
|
||||
import mogo.telematics.pad.MessagePad;
|
||||
|
||||
public class ArrivedStation {
|
||||
|
||||
public ArrivedStation(MogoLocation mogoLocation) {
|
||||
this.mogoLocation = mogoLocation;
|
||||
}
|
||||
|
||||
private MogoLocation mogoLocation;
|
||||
|
||||
public MogoLocation getEndLocation(){
|
||||
return mogoLocation;
|
||||
}
|
||||
|
||||
public static ArrivedStation trasform(MessagePad.ArrivalNotification arrivalNotification){
|
||||
MogoLocation mogoLocation = new MogoLocation();
|
||||
MessagePad.Location endLocation = arrivalNotification.getEndLocation();
|
||||
if(endLocation==null){
|
||||
return null;
|
||||
}
|
||||
mogoLocation.setLongitude(endLocation.getLongitude());
|
||||
mogoLocation.setLatitude(endLocation.getLatitude());
|
||||
|
||||
return new ArrivedStation(mogoLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArrivedStation{" +
|
||||
"mogoLocation=" + mogoLocation +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.mogo.och.bridge.autopilot.autopilot.bean
|
||||
|
||||
data class SessionWithTime(val sessionId:Long,val setTime:Long)
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.bridge.autopilot.callback
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/11/9
|
||||
*/
|
||||
interface OchAdasStartFailureCallback {
|
||||
fun onStartAutopilotFailure(startFailedCode : String, startFailedMessage : String)
|
||||
|
||||
fun onStartAutopilotSuccess(type:String)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.mogo.och.bridge.autopilot.line;
|
||||
|
||||
|
||||
public interface ILineCallback {
|
||||
default void clearLineSuccess(){}
|
||||
|
||||
default void drawLineSuccess(){}
|
||||
|
||||
default void drawLineFail(){}
|
||||
|
||||
default void sendStartAutopilotSuccess(){}
|
||||
|
||||
default void startAutopilotTimeOut(){}
|
||||
|
||||
default void sendStartAutopilotSuccessAck(){}
|
||||
|
||||
default void startAutopilotFailure(String startFailedCode,String startFailedMessage){}
|
||||
|
||||
default void startAutopilotSuccess(){}
|
||||
|
||||
default void arrivedStationSuccessBySearch(){}
|
||||
}
|
||||
@@ -0,0 +1,559 @@
|
||||
package com.mogo.och.bridge.autopilot.line
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.elegant.network.utils.GsonUtil
|
||||
import com.mogo.commons.env.ProjectUtils
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters.AutoPilotLine
|
||||
import com.mogo.eagle.core.data.autopilot.AutopilotControlParameters.AutoPilotLonLat
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.data.och.OchInfo
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.datacenter.CallerDataCenterBizListener
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapGlobalTrajectoryDrawManager
|
||||
import com.mogo.eagle.core.function.call.och.CallerEagleBaseFunctionCall4OchManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.e
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_BUS
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.StringUtils
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.common.module.constant.OchCommonConst
|
||||
import com.mogo.och.bridge.autopilot.OCHAdasAbilityManager
|
||||
import com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotManager
|
||||
import com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotManager.startAutoPilot
|
||||
import com.mogo.och.bridge.autopilot.autopilot.OchAutopilotAnalytics
|
||||
import com.mogo.och.bridge.autopilot.location.OchLocationManager
|
||||
import com.mogo.och.bridge.distance.TrajectoryAndDistanceManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.utils.CallerBase
|
||||
import com.mogo.och.common.module.voice.VoiceNotice
|
||||
import com.mogo.och.data.bean.BusStationBean
|
||||
import com.mogo.och.data.bean.ContraiInfo
|
||||
import com.mogo.och.data.bean.LineInfo
|
||||
import com.zhjt.mogo.adas.data.bean.ReceivedAck
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* 订单中
|
||||
*/
|
||||
object LineManager : CallerBase<ILineCallback>() {
|
||||
const val TAG = "LineManager"
|
||||
/**
|
||||
* 线路信息
|
||||
*/
|
||||
@JvmStatic
|
||||
private var _lineInfos: LineInfo? = null
|
||||
|
||||
val lineInfos:LineInfo?
|
||||
@JvmStatic
|
||||
get() = _lineInfos
|
||||
|
||||
/**
|
||||
* 启动自驾信息
|
||||
*/
|
||||
@JvmStatic
|
||||
private var _contraiInfo: ContraiInfo? = null
|
||||
val contraiInfo:ContraiInfo?
|
||||
@JvmStatic
|
||||
get() = _contraiInfo
|
||||
|
||||
|
||||
/**
|
||||
* 起始站点
|
||||
*/
|
||||
private var startStation: BusStationBean? = null
|
||||
|
||||
/**
|
||||
* 结束站点
|
||||
*/
|
||||
private var endStation: BusStationBean? = null
|
||||
|
||||
var isFirstStartAutopilot = true
|
||||
|
||||
/**
|
||||
* 线路、轨迹、站点 三者确定的id
|
||||
*/
|
||||
private var autopilotId: String by Delegates.observable("") { _, oldValue, newValue ->
|
||||
if (oldValue != newValue) {
|
||||
CallerEagleBaseFunctionCall4OchManager.setOchAutopilotOrderId(newValue)
|
||||
isFirstStartAutopilot = true
|
||||
if(!AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)&&!AppIdentityModeUtils.isShuttle(FunctionBuildConfig.appIdentityMode)){
|
||||
val (start, end) = getStations()
|
||||
if(start!=null&&end!=null){
|
||||
val ochInfo = OchInfo(0, mutableListOf(start.toMogoLocation(), end.toMogoLocation()))
|
||||
CallerDataCenterBizListener.invokeOchInfo(ochInfo)
|
||||
OchChainLogManager.writeChainLogMap("向地图传参数", "参数信息:${ochInfo}")
|
||||
}else{
|
||||
val ochInfo = OchInfo(0, mutableListOf())
|
||||
CallerDataCenterBizListener.invokeOchInfo(ochInfo)
|
||||
OchChainLogManager.writeChainLogMap("向地图传参数", "参数信息:${ochInfo}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 自车定位
|
||||
private val mMapLocationListener = object : IMoGoChassisLocationGCJ02Listener {
|
||||
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
|
||||
if (null == mogoLocation) return
|
||||
getStations { start, end ->
|
||||
val startLon = end.gcjLon
|
||||
val startLat = end.gcjLat
|
||||
val distance = CoordinateUtils.calculateLineDistance(
|
||||
startLon, startLat,
|
||||
mogoLocation.longitude, mogoLocation.latitude
|
||||
)
|
||||
if (distance <= OchCommonConst.ARRIVE_AT_END_STATION_DISTANCE) {
|
||||
val token = CallerAutoPilotControlManager.sendSsmFuncQueryAutoPilotStation(autopilotId)
|
||||
OchChainLogManager.writeChainLogAutopilot("到站逻辑","距离站点:$distance 请求token:$token")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun invokeArrivedStation(orderId: String, arrivedStationFlag: Boolean) {
|
||||
if (this.autopilotId==orderId&&arrivedStationFlag){
|
||||
M_LISTENERS.forEach {
|
||||
it.value.arrivedStationSuccessBySearch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun invokeSetIsFirstAutopilot(orderId: String?, firstAutopilotFlag: Boolean, count: Int) {
|
||||
if (this.autopilotId==orderId){
|
||||
if(count>=1){
|
||||
isFirstStartAutopilot = false
|
||||
}else{
|
||||
isFirstStartAutopilot = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置站点信息
|
||||
*/
|
||||
fun setStartAndEndStation(startStation: BusStationBean?, endStation: BusStationBean?) {
|
||||
if(this.startStation!=startStation||this.endStation!=endStation){
|
||||
isFirstStartAutopilot = true
|
||||
}
|
||||
this.startStation = startStation
|
||||
this.endStation = endStation
|
||||
if(startStation==null||endStation==null){
|
||||
clearAutopilotControlParameters()
|
||||
}else {
|
||||
setAutopilotControlParameters()
|
||||
}
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾参数", "站点信息:${startStation}---${endStation}")
|
||||
}
|
||||
|
||||
fun setContraiInfo(contraiInfo: ContraiInfo?){
|
||||
this._contraiInfo = contraiInfo
|
||||
setAutopilotControlParameters()
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾参数", "轨迹信息:${contraiInfo}")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setLineInfo(lineInfo: LineInfo?) {
|
||||
if (lineInfo == null) {
|
||||
clearGlobalTrajectory(true)
|
||||
CallerEagleBaseFunctionCall4OchManager.updateOrderLine("")
|
||||
}
|
||||
_lineInfos = lineInfo
|
||||
setAutopilotControlParameters()
|
||||
_lineInfos?.let { line ->
|
||||
if (ProjectUtils.isSaas()) {
|
||||
val sb = StringBuilder()
|
||||
sb.append(line.lineName)
|
||||
line.multiMap?.forEach {
|
||||
sb.append(it.value)
|
||||
}
|
||||
CallerEagleBaseFunctionCall4OchManager.updateOrderLine(sb.toString())
|
||||
}
|
||||
}
|
||||
OchChainLogManager.writeChainLogAutopilot("自驾参数", "线路信息:$contraiInfo")
|
||||
}
|
||||
|
||||
fun getStations(): Pair<BusStationBean?, BusStationBean?> {
|
||||
return Pair(startStation, endStation)
|
||||
}
|
||||
|
||||
fun getStations(function: (start: BusStationBean, end: BusStationBean) -> Unit) {
|
||||
startStation?.let { start ->
|
||||
endStation?.let { end ->
|
||||
function.invoke(start, end)
|
||||
return
|
||||
}
|
||||
}
|
||||
OchChainLogManager.writeChainLog("异常情况","startStation:${startStation}__endStation:$endStation")
|
||||
}
|
||||
|
||||
fun getStationsWithLine(function: (start: BusStationBean, end: BusStationBean, lineInfo: LineInfo) -> Unit) {
|
||||
startStation?.let { start ->
|
||||
endStation?.let { end ->
|
||||
_lineInfos?.let { line ->
|
||||
function.invoke(start, end, line)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
OchChainLogManager.writeChainLog(
|
||||
"异常情况",
|
||||
"startStation:${startStation}__endStation:${endStation}__lineInfos:$_lineInfos"
|
||||
)
|
||||
}
|
||||
|
||||
fun getStationsWithLineAndContrai(function: (start: BusStationBean, end: BusStationBean, lineInfo: LineInfo, contrai: ContraiInfo) -> Unit) {
|
||||
startStation?.let { start ->
|
||||
endStation?.let { end ->
|
||||
_lineInfos?.let { line ->
|
||||
_contraiInfo?.let { contrai ->
|
||||
function.invoke(start, end, line, contrai)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OchChainLogManager.writeChainLog(
|
||||
"异常情况",
|
||||
"startStation:${startStation}__endStation:${endStation}__lineInfos:${_lineInfos}__contraiInfo:$_contraiInfo"
|
||||
)
|
||||
}
|
||||
|
||||
fun getStartStation(function: (start: BusStationBean) -> Unit) {
|
||||
startStation?.let { start ->
|
||||
function.invoke(start)
|
||||
return
|
||||
}
|
||||
OchChainLogManager.writeChainLog("异常情况", "startStation:$startStation")
|
||||
}
|
||||
|
||||
fun getLineInfo(function: (lineInfo: LineInfo) -> Unit){
|
||||
_lineInfos?.let { line->
|
||||
function.invoke(line)
|
||||
return
|
||||
}
|
||||
OchChainLogManager.writeChainLog("异常情况", "lineInfos:$_lineInfos")
|
||||
}
|
||||
|
||||
|
||||
override fun doSomeAfterAddListener(tag: String, listener: ILineCallback) {
|
||||
super.doSomeAfterAddListener(tag, listener)
|
||||
if (hasDrawnGlobalTrajectory()) {
|
||||
listener.drawLineSuccess()
|
||||
} else {
|
||||
listener.drawLineFail()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAutopilotControlParameters(){
|
||||
getStationsWithLineAndContrai { start, end, lineInfo, contrai ->
|
||||
val parameters = initAutopilotControlParameters()
|
||||
if (null == parameters) {
|
||||
e(M_BUS + TAG, "AutopilotControlParameters is empty.")
|
||||
return@getStationsWithLineAndContrai
|
||||
}
|
||||
d(M_BUS + TAG, "AutopilotControlParameters is update.")
|
||||
CallerAutoPilotStatusListenerManager.updateAutopilotControlParameters(parameters)
|
||||
val startStationLocation = MogoLocation()
|
||||
startStationLocation.latitude = start.gcjLat
|
||||
startStationLocation.longitude = start.gcjLon
|
||||
|
||||
val endStationLocation = MogoLocation()
|
||||
endStationLocation.latitude = end.gcjLat
|
||||
endStationLocation.longitude = end.gcjLon
|
||||
TrajectoryAndDistanceManager.setStationPoint(startStationLocation, endStationLocation, lineInfo.lineId)
|
||||
OchLocationManager.addGCJ02Listener(TAG,1, mMapLocationListener)
|
||||
// 恢复启动自驾信息
|
||||
searchAutopilotState()
|
||||
}
|
||||
}
|
||||
fun searchAutopilotState(){
|
||||
CallerAutoPilotControlManager.sendSsmFuncQueryAutoPilotInfo()
|
||||
}
|
||||
private fun clearAutopilotControlParameters(){
|
||||
CallerAutoPilotStatusListenerManager.updateAutopilotControlParameters(null)
|
||||
TrajectoryAndDistanceManager.setStationPoint(null, null, null)
|
||||
autopilotId = ""
|
||||
OchLocationManager.removeGCJ02Listener(TAG)
|
||||
}
|
||||
|
||||
fun hasDrawnGlobalTrajectory(): Boolean {
|
||||
return CallerMapGlobalTrajectoryDrawManager.hasDrawnGlobalTrajectory()
|
||||
}
|
||||
|
||||
fun clearGlobalTrajectory(isClearData: Boolean) {
|
||||
CallerMapGlobalTrajectoryDrawManager.clearGlobalTrajectory(isClearData)
|
||||
if (!hasDrawnGlobalTrajectory()) {
|
||||
M_LISTENERS.forEach {
|
||||
it.value.clearLineSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun drawGlobalTrajectory(): Pair<Boolean, String> {
|
||||
if (_lineInfos == null) {
|
||||
return Pair(false, "请设置正确线路或订单")
|
||||
}
|
||||
return CallerMapGlobalTrajectoryDrawManager.drawGlobalTrajectory().apply {
|
||||
if (first) {
|
||||
M_LISTENERS.forEach {
|
||||
it.value.drawLineSuccess()
|
||||
}
|
||||
} else {
|
||||
M_LISTENERS.forEach {
|
||||
it.value.drawLineFail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun initAutopilotControlParameters(): AutopilotControlParameters? {
|
||||
var parameters: AutopilotControlParameters? = null
|
||||
getStationsWithLineAndContrai { start, end, lineInfo, contrai ->
|
||||
parameters = AutopilotControlParameters()
|
||||
parameters?.routeID = lineInfo.lineId.toInt()
|
||||
parameters?.routeName = lineInfo.lineName
|
||||
parameters?.startName = start.name
|
||||
parameters?.endName = end.name
|
||||
parameters?.startLatLon = AutoPilotLonLat(start.lat, start.lon)
|
||||
parameters?.endLatLon = AutoPilotLonLat(end.lat, end.lon)
|
||||
parameters?.vehicleType = 10
|
||||
autopilotId = "${lineInfo.lineId}_${start.siteId}_${end.siteId}_${lineInfo.orderId}"
|
||||
parameters?.orderId = autopilotId
|
||||
parameters?.firstAutopilotFlag = isFirstStartAutopilot
|
||||
|
||||
if (parameters?.autoPilotLine == null) {
|
||||
parameters?.autoPilotLine = AutoPilotLine(
|
||||
lineInfo.lineId,
|
||||
lineInfo.lineName,
|
||||
contrai.csvFileUrl,
|
||||
contrai.csvFileMd5,
|
||||
contrai.txtFileUrl,
|
||||
contrai.txtFileMd5,
|
||||
contrai.contrailSaveTime,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0L
|
||||
)
|
||||
}
|
||||
|
||||
val (wayLatLons, blackLatLons) = getWayBlackLatLons(contrai.passPoints, contrai.blackPoints)
|
||||
|
||||
parameters?.wayLatLons = wayLatLons
|
||||
parameters?.blackLatLons = blackLatLons
|
||||
|
||||
}
|
||||
if (parameters == null) {
|
||||
ToastUtils.showShort("未设置起始或终点站点")
|
||||
}
|
||||
return parameters
|
||||
}
|
||||
|
||||
fun getWayBlackLatLons(
|
||||
passPoints: MutableList<BusStationBean>?,
|
||||
blackPoints: MutableList<BusStationBean>?
|
||||
): Pair<MutableList<AutoPilotLonLat>, MutableList<AutoPilotLonLat>> {
|
||||
val wayLatLons = mutableListOf<AutoPilotLonLat>()
|
||||
// 途经点
|
||||
if (!passPoints.isNullOrEmpty()) {
|
||||
for (mogoLatLng in passPoints) {
|
||||
wayLatLons.add(
|
||||
AutoPilotLonLat(
|
||||
mogoLatLng.lat,
|
||||
mogoLatLng.lon,
|
||||
when (mogoLatLng.pointType) {
|
||||
1 -> {//途径点
|
||||
false
|
||||
}
|
||||
|
||||
2 -> {//禁行点
|
||||
false
|
||||
}
|
||||
|
||||
3 -> {//站点
|
||||
true
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
val blackLatLons = mutableListOf<AutoPilotLonLat>()
|
||||
// 黑名单点
|
||||
if (!blackPoints.isNullOrEmpty()) {
|
||||
for (mogoLatLng in blackPoints) {
|
||||
blackLatLons.add(
|
||||
AutoPilotLonLat(
|
||||
mogoLatLng.lat,
|
||||
mogoLatLng.lat,
|
||||
when (mogoLatLng.pointType) {
|
||||
1 -> {//途径点
|
||||
false
|
||||
}
|
||||
|
||||
2 -> {//禁行点
|
||||
false
|
||||
}
|
||||
|
||||
3 -> {//站点
|
||||
true
|
||||
}
|
||||
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return Pair(wayLatLons,blackLatLons)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 启动自动驾驶
|
||||
fun startAutopilot() {
|
||||
|
||||
if(startStation ==null|| endStation ==null){
|
||||
ToastUtils.showShort("未设置起始或终点站点")
|
||||
return
|
||||
}
|
||||
|
||||
startStation?.let {
|
||||
if(!it.isLeaving){
|
||||
ToastUtils.showShort("请滑动出发后再启动自驾")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 存在Session
|
||||
*/
|
||||
if (!OchAutoPilotManager.canStartAutopilotBySessionId()) {
|
||||
return
|
||||
}
|
||||
|
||||
OchAutopilotAnalytics.triggerClickStartAutopilotTime(System.currentTimeMillis())
|
||||
|
||||
//1、判断轨迹url是否可用
|
||||
if(_contraiInfo ==null){
|
||||
ToastUtils.showLong("无发布轨迹, 请发布后重试")
|
||||
return
|
||||
}else{
|
||||
if (FunctionBuildConfig.isPassStartAutopilotCommand
|
||||
&& TextUtils.isEmpty(_contraiInfo!!.csvFileUrl)
|
||||
&& TextUtils.isEmpty(_contraiInfo!!.csvFileMd5)
|
||||
) {
|
||||
ToastUtils.showLong("无发布轨迹, 请发布后重试")
|
||||
e(
|
||||
TAG, "isPassStartAutopilotCommand = " +
|
||||
FunctionBuildConfig.isPassStartAutopilotCommand
|
||||
+ "busRoutesResult.csvFileUrl = " + _contraiInfo!!.csvFileUrl
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//2、6个条件判断
|
||||
if (!CallerAutoPilotControlManager.isCanStartAutopilot(true, 0)) {
|
||||
return
|
||||
}
|
||||
|
||||
// 3、距离轨迹15m计算
|
||||
val resion = OchAutoPilotManager.canStartAutoPilotByDistance(_contraiInfo!!.lineId)
|
||||
if (!StringUtils.isEmpty(resion)) {
|
||||
ToastUtils.showShort(resion)
|
||||
VoiceNotice.showNotice(resion)
|
||||
return
|
||||
}
|
||||
//4、ssm 给出数据
|
||||
if (!OchAutoPilotManager.canStartAutoPilotSSM()) {
|
||||
triggerUnableStartAPReasonEvent()
|
||||
return
|
||||
}
|
||||
|
||||
triggerStartServiceEvent(false,0,"")
|
||||
|
||||
val parameters = initAutopilotControlParameters()
|
||||
if (null == parameters) {
|
||||
e(M_BUS + TAG, "行程日志-AutopilotControlParameters is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
val sessionId = startAutoPilot(parameters)
|
||||
OchAutopilotAnalytics.triggerUpdateStartAutoPilotSessionId(sessionId)
|
||||
|
||||
d(
|
||||
M_BUS + TAG,
|
||||
"行程日志-开启自动驾驶====" + GsonUtil.jsonFromObject(parameters)
|
||||
+ " startLatLon=" + parameters.startName + ",endLatLon=" + parameters.endName +
|
||||
"isRestart = " + isFirstStartAutopilot
|
||||
)
|
||||
|
||||
M_LISTENERS.forEach {
|
||||
it.value.sendStartAutopilotSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun triggerUnableStartAPReasonEvent() {
|
||||
getStationsWithLine { start, end, line ->
|
||||
OchAutopilotAnalytics.triggerUnableStartAPReasonEvent(
|
||||
start.name, end.name,line.lineId.toString() , "",
|
||||
OCHAdasAbilityManager.getInstance().autopilotUnAbilityReason
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun triggerStartServiceEvent(send: Boolean,source:Int,type:String) {
|
||||
getStationsWithLine { start, end, lineInfo ->
|
||||
OchAutopilotAnalytics.triggerStartAutopilotEvent(
|
||||
isFirstStartAutopilot,
|
||||
send,
|
||||
start.name,
|
||||
end.name,
|
||||
lineInfo.lineId.toInt(),
|
||||
"",
|
||||
System.currentTimeMillis(),
|
||||
type,
|
||||
source
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun invokeStartAutopilotTimeOut(){
|
||||
M_LISTENERS.forEach {
|
||||
it.value.startAutopilotTimeOut()
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun invokeStartAutopilotFailure(startFailedCode: String, startFailedMessage: String) {
|
||||
OchAutopilotAnalytics.triggerStartAutopilotFailureEventByAdas(startFailedCode,startFailedMessage,System.currentTimeMillis())
|
||||
M_LISTENERS.forEach {
|
||||
it.value.startAutopilotFailure(startFailedCode,startFailedMessage)
|
||||
}
|
||||
}
|
||||
|
||||
fun invokeStartAutopilotAckSuccess(receivedAck: ReceivedAck) {
|
||||
M_LISTENERS.forEach {
|
||||
it.value.sendStartAutopilotSuccessAck()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.mogo.och.bridge.autopilot.location
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationWGS84Listener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationGCJ02ListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisLocationWGS84ListenerManager
|
||||
|
||||
object OchLocationManager {
|
||||
|
||||
@JvmStatic
|
||||
fun getGCJ02Location(): MogoLocation {
|
||||
return CallerChassisLocationGCJ02ListenerManager.getChassisLocationGCJ02()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getWgs02Location():MogoLocation {
|
||||
return CallerChassisLocationWGS84ListenerManager.getChassisLocationWGS84()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun addGCJ02Listener(tag:String,callBackHz:Int,listener: IMoGoChassisLocationGCJ02Listener){
|
||||
CallerChassisLocationGCJ02ListenerManager.addListener(tag, callBackHz, listener)
|
||||
}
|
||||
@JvmStatic
|
||||
fun removeGCJ02Listener(tag:String){
|
||||
CallerChassisLocationGCJ02ListenerManager.removeListener(tag)
|
||||
}
|
||||
@JvmStatic
|
||||
fun removeGCJ02Listener(listener: IMoGoChassisLocationGCJ02Listener){
|
||||
CallerChassisLocationGCJ02ListenerManager.removeListener(listener)
|
||||
}
|
||||
@JvmStatic
|
||||
fun addWgs02Listener(tag:String,callBackHz:Int,listener: IMoGoChassisLocationWGS84Listener){
|
||||
CallerChassisLocationWGS84ListenerManager.addListener(tag, callBackHz, listener)
|
||||
}
|
||||
@JvmStatic
|
||||
fun removeWgs02Listener(tag:String){
|
||||
CallerChassisLocationWGS84ListenerManager.removeListener(tag)
|
||||
}
|
||||
@JvmStatic
|
||||
fun removeWgs02Listener(listener: IMoGoChassisLocationWGS84Listener){
|
||||
CallerChassisLocationWGS84ListenerManager.removeListener(listener)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.mogo.och.bridge.autopilot.trajectory
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
|
||||
interface ITrajectoryListListener{
|
||||
/**
|
||||
* @param trajectoryList gcj 坐标轨迹集合
|
||||
*/
|
||||
fun trajectoryCallback(trajectoryList: MutableList<MogoLocation>){}
|
||||
|
||||
/**
|
||||
* @param maxDistanceAllPoint 轨迹全长
|
||||
*/
|
||||
fun trajectoryDistanceCallback(maxDistanceAllPoint: Double){}
|
||||
// 开始下载轨迹
|
||||
fun onDownLoadStart(lineId: Long){}
|
||||
// 下载轨迹成功
|
||||
fun onDownLoadSuccess(lineId: Long){}
|
||||
// 下载轨迹是吧
|
||||
fun onDownLoadFail(lineId: Long){}
|
||||
// 下载轨迹超时
|
||||
fun onDownLoadTimeout(lineId: Long){}
|
||||
// 加载轨迹失败
|
||||
fun onLoadFail(lineId: Long){}
|
||||
// 轨迹不存在
|
||||
fun onTrajectoryNotExist(lineId: Long){}
|
||||
// 底盘已就行
|
||||
fun onDownLoadReady(lineId: Long) {}
|
||||
|
||||
// 当前位置距离轨迹大于15m
|
||||
fun onDistanceWithTrajectory(lineId: Long) {}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mogo.och.bridge.autopilot.trajectory
|
||||
|
||||
import com.elegant.network.utils.GsonUtil
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OCHCOMMON
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.FileWriter
|
||||
import java.io.IOException
|
||||
|
||||
object TrajectoryCache {
|
||||
|
||||
private const val TAG = "TrajectoryCache"
|
||||
|
||||
private val dir = "${AbsMogoApplication.getApp().cacheDir}/trajectory/"
|
||||
|
||||
fun writeLastTrajectory2jsonFile(latLngModels: MutableList<MogoLocation>,name:String) {
|
||||
val jsonFromObject = GsonUtil.jsonFromObject(latLngModels)
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(!path.exists()){
|
||||
path.mkdir()
|
||||
}else {
|
||||
path.deleteRecursively()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"删除缓存:${name}")
|
||||
path.mkdir()
|
||||
}
|
||||
val writer = FileWriter("${path.path}/${name}")
|
||||
writer.write(jsonFromObject)
|
||||
writer.close()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"写入缓存:${name}")
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteCatcheFile(){
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(path.exists()){
|
||||
path.deleteRecursively()
|
||||
CallerLogger.d(M_OCHCOMMON + TAG,"删除缓存")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun redCatche(name: String): MutableList<MogoLocation>? {
|
||||
try {
|
||||
val path = File(dir)
|
||||
if(!path.exists()){
|
||||
return null
|
||||
}
|
||||
val fileReader = FileReader("${path.path}/${name}")
|
||||
val readText = fileReader.readText()
|
||||
fileReader.close()
|
||||
return GsonUtil.arrayFromJson(readText, MogoLocation::class.java)
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
package com.mogo.och.bridge.autopilot.trajectory
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager.writeChainLog
|
||||
import com.mogo.och.common.module.utils.CallerBase
|
||||
import com.mogo.och.bridge.utils.CoordinateCalculateRouteUtil
|
||||
import com.zhjt.mogo.adas.data.bean.MogoReport
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
object TrajectoryManager : CallerBase<ITrajectoryListListener>(),IMoGoPlanningRottingListener {
|
||||
const val TAG = "TrajectoryManager"
|
||||
|
||||
private val downLoadSuccessLineIds = mutableListOf<Long>()
|
||||
|
||||
/**
|
||||
* 所有轨迹点
|
||||
*/
|
||||
@Volatile
|
||||
var mRoutePoints = mutableListOf<MogoLocation>()
|
||||
|
||||
/**
|
||||
* 0-1 1-2 2-3 各个轨迹点的距离
|
||||
*/
|
||||
@Volatile
|
||||
private var mRoutePointsDistance: MutableList<Float>? = ArrayList()
|
||||
|
||||
/**
|
||||
* 所有轨迹点距离的和
|
||||
*/
|
||||
@Volatile
|
||||
private var maxDistanceAllPoint: Double = 0.0
|
||||
|
||||
init {
|
||||
CallerPlanningRottingListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
private var lineId:Long?=0
|
||||
|
||||
override fun onAutopilotRotting(globalPathResp: MessagePad.GlobalPathResp?) {
|
||||
CallerLogger.d(SceneConstant.M_OCHCOMMON + TAG, "onAutopilotRotting: 收到轨迹")
|
||||
globalPathResp?.wayPointsList?.let {
|
||||
if (it.size > 0) {
|
||||
CallerLogger.d(
|
||||
SceneConstant.M_OCHCOMMON + TAG,
|
||||
"收到轨迹:轨迹个数${it.size}第一个点${it[0]}最后一个点:${it.last()} 轨迹id:${globalPathResp.lineId}"
|
||||
)
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (globalPathResp.lineId != null) {// 适配低版本不传递lineId
|
||||
if (globalPathResp.lineId == lineId) {
|
||||
CallerLogger.d(SceneConstant.M_OCHCOMMON + TAG, "重复轨迹")
|
||||
return
|
||||
}
|
||||
lineId = globalPathResp.lineId
|
||||
}
|
||||
updateRoutePoints(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRoutePoints(routePoints: List<MessagePad.Location>?) {
|
||||
mRoutePointsDistance = null
|
||||
val latLngModels = CoordinateCalculateRouteUtil
|
||||
.coordinateConverterWgsToGcjLocations(AbsMogoApplication.getApp(), routePoints!!)
|
||||
mRoutePoints = latLngModels
|
||||
|
||||
mRoutePointsDistance = ArrayList()
|
||||
maxDistanceAllPoint = 0.0
|
||||
mRoutePoints.forEachIndexed { index, current ->
|
||||
if (mRoutePoints.last() != current) {
|
||||
val next = mRoutePoints[index + 1]
|
||||
val distanceItem = CoordinateUtils.calculateLineDistance(
|
||||
current.longitude,
|
||||
current.latitude,
|
||||
next.longitude,
|
||||
next.latitude
|
||||
)
|
||||
mRoutePointsDistance?.add(distanceItem)
|
||||
maxDistanceAllPoint += distanceItem
|
||||
}
|
||||
}
|
||||
M_LISTENERS.forEach {
|
||||
it.value.trajectoryCallback(mRoutePoints)
|
||||
}
|
||||
M_LISTENERS.forEach {
|
||||
it.value.trajectoryDistanceCallback(maxDistanceAllPoint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDownLoadSuccessLine(lineId:Long){
|
||||
if(lineId>0){
|
||||
OchChainLogManager.writeChainLog("轨迹监控", " 轨迹下载成功${lineId}", true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY)
|
||||
downLoadSuccessLineIds.add(lineId)
|
||||
}
|
||||
}
|
||||
private fun removeDownLoadSuccessLine(lineId:Long){
|
||||
if(lineId>0&& downLoadSuccessLineIds.contains(lineId)){
|
||||
downLoadSuccessLineIds.remove(lineId)
|
||||
}
|
||||
}
|
||||
|
||||
fun carDownLoadTrajectoryLog(code: String?, lineId: Long){
|
||||
when (code) {
|
||||
MogoReport.Code.Info.ISYS.INIT_TRAJECTORY_START -> {
|
||||
writeTrajectoryLog("轨迹开始下载")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadStart(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Info.ISYS.INIT_TRAJECTORY_SUCCESS -> {
|
||||
writeTrajectoryLog("轨迹下载成功")
|
||||
addDownLoadSuccessLine(lineId)
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadSuccess(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Info.ISYS.INIT_TRAJECTORY_FAILURE -> {
|
||||
writeTrajectoryLog("轨迹下载失败,本地无对应轨迹")
|
||||
// 更新轨迹没有更新lineId 第二次下载失败 删除App成功缓存(概率很低)
|
||||
removeDownLoadSuccessLine(lineId)
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadFail(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Info.ISYS.INIT_TRAJECTORY_WARNING -> {
|
||||
writeTrajectoryLog("轨迹下载失败,本地有对应轨迹,认为成功")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadSuccess(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Info.ISYS.INIT_TRAJECTORY_TIMEOUT -> {
|
||||
writeTrajectoryLog("轨迹下载超时")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadTimeout(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Info.ISSM.FUNC_AUTO_PILOT_READY -> {
|
||||
writeTrajectoryLog("再次发起下载、 ssm ready,再次发起下载")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDownLoadReady(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Error.EMAP.TRA_LOAD_FAILED -> {
|
||||
writeTrajectoryLog("onAutopilotGuardian() 加载轨迹文件失败")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onLoadFail(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Error.EMAP.TRA_NOT_EXIST -> {
|
||||
writeTrajectoryLog("onAutopilotGuardian() 无法找到轨迹文件")
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onTrajectoryNotExist(lineId)
|
||||
}
|
||||
}
|
||||
MogoReport.Code.Error.EMAP.ATTITUDE_INIT_FAILED->{
|
||||
writeTrajectoryLog("onAutopilotGuardian() 当前位置距离轨迹距离大于15m")
|
||||
|
||||
M_LISTENERS.forEach {
|
||||
it.value.onDistanceWithTrajectory(lineId)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeTrajectoryLog(message:String){
|
||||
writeChainLog("轨迹监控", message, true, OchChainLogManager.EVENT_KEY_INFE_WITH_TRAJECTORY)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.mogo.och.bridge.device
|
||||
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.och.bridge.autopilot.location.OchLocationManager
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import com.mogo.och.common.module.wigets.toast.ToastCharterUtils
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
object LightAirconditionDoorManager {
|
||||
private const val TAG = "LightAirconditionDoorManager"
|
||||
|
||||
private var dooorSubscribe: Disposable? = null
|
||||
|
||||
fun go2OpenDoor(go2Open:Boolean){
|
||||
val canOpenOrCloseDoor = canOpenOrCloseDoor()
|
||||
if(!canOpenOrCloseDoor.isNullOrBlank()){
|
||||
ToastCharterUtils.showToastLong(canOpenOrCloseDoor)
|
||||
return
|
||||
}
|
||||
RxUtils.disposeSubscribe(dooorSubscribe)
|
||||
dooorSubscribe = RxUtils.createSubscribe(1000) {
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(0)
|
||||
}
|
||||
if(go2Open) {
|
||||
if (LightAirconditionDoorStatusManager.doorStatus.isOpen) {
|
||||
return
|
||||
}
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(1)
|
||||
}else{
|
||||
if (!LightAirconditionDoorStatusManager.doorStatus.isOpen) {
|
||||
return
|
||||
}
|
||||
CallerAutoPilotControlManager.sendRoboBusJinlvM1FrontDoorCmd(2)
|
||||
}
|
||||
}
|
||||
|
||||
private fun canOpenOrCloseDoor(): String? {
|
||||
val location = OchLocationManager.getGCJ02Location()
|
||||
return if(location.gnssSpeed<0.3){
|
||||
null
|
||||
}else{
|
||||
"车辆行驶中不可以开关门哦~"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.mogo.och.bridge.device
|
||||
|
||||
import chassis.VehicleStateOuterClass
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoRoboBusJinlvM1StatesListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerRoboBusJinlvM1StatesListenerManager
|
||||
import com.mogo.och.bridge.device.callback.LightAirconditionDoorCallback
|
||||
import com.mogo.och.bridge.device.data.AirconditionStatus
|
||||
import com.mogo.och.bridge.device.data.DoorStatus
|
||||
import com.mogo.och.bridge.device.data.HeaterStatue
|
||||
import com.mogo.och.bridge.device.data.LightStatus
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
object LightAirconditionDoorStatusManager : IMoGoRoboBusJinlvM1StatesListener {
|
||||
private const val TAG = "OCHM1LightAirconditionDoorStatusManager"
|
||||
|
||||
init {
|
||||
CallerRoboBusJinlvM1StatesListenerManager.addListener(TAG, this)
|
||||
CallerRoboBusJinlvM1StatesListenerManager.setListenerHz(TAG,5)
|
||||
}
|
||||
|
||||
val M_LISTENERS: ConcurrentHashMap<String, LightAirconditionDoorCallback> =
|
||||
ConcurrentHashMap()
|
||||
|
||||
val airconditionStatus = AirconditionStatus(false, 0, 26, 2)
|
||||
val heaterStatue = HeaterStatue(false, 2)
|
||||
val doorStatus = DoorStatus(false)
|
||||
val lightStatus = LightStatus(false, false, false)
|
||||
|
||||
fun addListener(
|
||||
tag: String,
|
||||
listener: LightAirconditionDoorCallback
|
||||
) {
|
||||
if (M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS[tag] = listener
|
||||
listener.onLightTop1Callback(lightStatus,true)
|
||||
listener.onLightTop2Callback(lightStatus,true)
|
||||
listener.onLightAtmosphereCallback(lightStatus,true)
|
||||
listener.onAirconditionStatusCallback(heaterStatue.isOpen, airconditionStatus,true)
|
||||
listener.onHeaterStatusCallback(airconditionStatus.isOpen, heaterStatue,true)
|
||||
}
|
||||
|
||||
fun removeListener(tag: String) {
|
||||
if (!M_LISTENERS.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.remove(tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除监听
|
||||
* @param listener 要删除的监听对象
|
||||
*/
|
||||
fun removeListener(listener: LightAirconditionDoorCallback) {
|
||||
if (!M_LISTENERS.containsValue(listener)) {
|
||||
return
|
||||
}
|
||||
M_LISTENERS.forEach {
|
||||
if (it.value == listener) {
|
||||
M_LISTENERS.remove(it.key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRoboBusJinlvM1States(states: VehicleStateOuterClass.RoboBusJinlvM1State) {
|
||||
val airConditionerState = states.airConditionerState
|
||||
val heaterState = states.heaterState
|
||||
if (airConditionerState.isOn != airconditionStatus.isOpen ||
|
||||
airConditionerState.mode != airconditionStatus.pattert ||
|
||||
airConditionerState.temperature != airconditionStatus.temperature ||
|
||||
airConditionerState.windSpeed != airconditionStatus.windSpeed
|
||||
) {
|
||||
airconditionStatus.isOpen = airConditionerState.isOn
|
||||
airconditionStatus.pattert = airConditionerState.mode
|
||||
airconditionStatus.temperature = airConditionerState.temperature
|
||||
airconditionStatus.windSpeed = airConditionerState.windSpeed
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onAirconditionStatusCallback(heaterState.isOn, airconditionStatus,false)
|
||||
}
|
||||
}
|
||||
if (heaterState.isOn != heaterStatue.isOpen ||
|
||||
heaterState.windSpeed != heaterStatue.windSpeed
|
||||
) {
|
||||
heaterStatue.isOpen = heaterState.isOn
|
||||
heaterStatue.windSpeed = heaterState.windSpeed
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onHeaterStatusCallback(airConditionerState.isOn, heaterStatue,false)
|
||||
}
|
||||
}
|
||||
if (states.frontDoorState.isOn != doorStatus.isOpen) {
|
||||
doorStatus.isOpen = states.frontDoorState.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onDoorStatusCallback(doorStatus.isOpen,false)
|
||||
}
|
||||
}
|
||||
if(states.mainLamp1State.isOn != lightStatus.isOpenLight1){
|
||||
lightStatus.isOpenLight1 = states.mainLamp1State.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightTop1Callback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
if(states.mainLamp2State.isOn != lightStatus.isOpenLight2){
|
||||
lightStatus.isOpenLight2 = states.mainLamp2State.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightTop2Callback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
if(states.smallLampState.isOn != lightStatus.isOpenatmosphere){
|
||||
lightStatus.isOpenatmosphere = states.smallLampState.isOn
|
||||
M_LISTENERS.forEach {
|
||||
val tag = it.key
|
||||
val listener = it.value
|
||||
listener.onLightAtmosphereCallback(lightStatus,false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.mogo.och.bridge.device
|
||||
|
||||
import chassis.Chassis
|
||||
import chassis.VehicleStateOuterClass
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisDoorStateListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerChassisDoorStateListenerManager
|
||||
import com.mogo.eagle.core.function.call.base.CallerBase
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.och.bridge.device.callback.DoorStateCallback
|
||||
import com.mogo.och.bridge.device.data.DoorPosition
|
||||
import com.mogo.och.bridge.device.data.DoorState
|
||||
|
||||
object TaxiDoorStateManager : IMoGoChassisDoorStateListener,
|
||||
CallerBase<DoorStateCallback>() {
|
||||
private val TAG = TaxiDoorStateManager::class.java.simpleName
|
||||
|
||||
@Volatile
|
||||
private var haveOpenDoor: Boolean? = null
|
||||
|
||||
init {
|
||||
CallerChassisDoorStateListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun doSomeAfterAddListener(tag: String, listener: DoorStateCallback) {
|
||||
val doorList = CallerChassisDoorStateListenerManager.getDoorList()
|
||||
if(doorList is MutableList<VehicleStateOuterClass.DoorStateV2>){
|
||||
doSomeAfterAddListenerInner(doorList)
|
||||
doorList.forEach {
|
||||
onAutopilotSingleDoorState(it.number,it.status)
|
||||
}
|
||||
}else{
|
||||
doSomeAfterAddListenerInner(mutableListOf())
|
||||
}
|
||||
}
|
||||
|
||||
private fun doSomeAfterAddListenerInner(doorList: MutableList<VehicleStateOuterClass.DoorStateV2>){
|
||||
var have = false
|
||||
doorList.forEach {
|
||||
if (it.status == 1) {//0关闭 1开着 2未知
|
||||
have = true
|
||||
}
|
||||
}
|
||||
haveOpenDoor = have
|
||||
invokeOpenState(have)
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要用来判断是否有门开着
|
||||
*/
|
||||
override fun onAutopilotDoorState(doorList: MutableList<VehicleStateOuterClass.DoorStateV2>) {
|
||||
var have = false
|
||||
doorList.forEach {
|
||||
if (it.status == 1) {//0关闭 1开着 2未知
|
||||
have = true
|
||||
}
|
||||
}
|
||||
if (have != haveOpenDoor) {
|
||||
haveOpenDoor = have
|
||||
invokeOpenState(have)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断单个车门是否开着
|
||||
*/
|
||||
override fun onAutopilotSingleDoorState(num: Chassis.DoorNumber, status: Int) {
|
||||
CallerLogger.d(SceneConstant.M_TAXI_P + TAG, "门太变化:${num}--${status}")
|
||||
when (status) {
|
||||
0 -> { exchangeEnum(num, DoorState.CLOSE)
|
||||
}
|
||||
1 -> {
|
||||
exchangeEnum(num, DoorState.OPEN)
|
||||
}
|
||||
2 -> {
|
||||
exchangeEnum(num, DoorState.UNKNOWN)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun exchangeEnum(num: Chassis.DoorNumber, state: DoorState) {
|
||||
when (num) {
|
||||
Chassis.DoorNumber.FRONT_LEFT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.FRONT_LEFT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.FRONT_RIGHT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.FRONT_RIGHT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.REAR_LEFT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.REAR_LEFT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.REAR_RIGHT -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.REAR_RIGHT, state)
|
||||
}
|
||||
|
||||
Chassis.DoorNumber.MIDDLE -> {
|
||||
invokeSingleDoorOpenState(DoorPosition.MIDDLE, state)
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param have true 有车门开着
|
||||
* false 没有车门开着(可能开着可能未知)
|
||||
*/
|
||||
@Synchronized
|
||||
private fun invokeOpenState(have: Boolean) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.hasOpenDoor(have)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param doorPosition 车门位置
|
||||
* @param doorState 车门状态
|
||||
*/
|
||||
@Synchronized
|
||||
private fun invokeSingleDoorOpenState(doorPosition: DoorPosition, doorState: DoorState) {
|
||||
M_LISTENERS.forEach {
|
||||
val listener = it.value
|
||||
listener.doorStateChangeCallback(doorPosition,doorState)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.mogo.och.bridge.device.callback
|
||||
|
||||
import com.mogo.och.bridge.device.data.DoorPosition
|
||||
import com.mogo.och.bridge.device.data.DoorState
|
||||
|
||||
interface DoorStateCallback {
|
||||
|
||||
/**
|
||||
* @param have true 有车门开着
|
||||
* false 没有车门开着(可能开着可能未知)
|
||||
*/
|
||||
fun hasOpenDoor(have:Boolean){}
|
||||
|
||||
/**
|
||||
* @param position 车门位置
|
||||
* @param state 当前车门状态
|
||||
*/
|
||||
fun doorStateChangeCallback(position: DoorPosition, state: DoorState){}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.mogo.och.bridge.device.callback
|
||||
|
||||
import com.mogo.och.bridge.device.data.AirconditionStatus
|
||||
import com.mogo.och.bridge.device.data.HeaterStatue
|
||||
import com.mogo.och.bridge.device.data.LightStatus
|
||||
|
||||
interface LightAirconditionDoorCallback {
|
||||
|
||||
fun onAirconditionStatusCallback(heaterIsOpen: Boolean, airconditionStatus: AirconditionStatus,
|
||||
isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onHeaterStatusCallback(airconditionIsOpen: Boolean, heaterStatue: HeaterStatue,
|
||||
isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onDoorStatusCallback(isOpen: Boolean, isFirst: Boolean) {}
|
||||
|
||||
fun onLightTop1Callback(lightStatus: LightStatus, isFirst: Boolean) {
|
||||
}
|
||||
|
||||
fun onLightTop2Callback(lightStatus: LightStatus, isFirst: Boolean) {}
|
||||
|
||||
fun onLightAtmosphereCallback(lightStatus: LightStatus, isFirst: Boolean) {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.mogo.och.bridge.device.checkvin
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import com.mogo.eagle.core.function.hmi.dialog.BaseFloatDialog
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.och.bridge.R
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import kotlinx.android.synthetic.main.common_checkvin_view.actv_see
|
||||
|
||||
class CheckVinErrorDialog(context: Context) : BaseFloatDialog(context), LifecycleObserver {
|
||||
|
||||
companion object{
|
||||
const val EVENT_KEY_INFO_CHECK_VIN = "analytics_event_och_check_vin"
|
||||
}
|
||||
|
||||
init {
|
||||
setContentView(R.layout.common_checkvin_view)
|
||||
setCanceledOnTouchOutside(true)
|
||||
|
||||
actv_see.onClick {
|
||||
OchChainLogManager.writeChainLog("vinCheck","用户点击了 ”我知道了“",true,
|
||||
EVENT_KEY_INFO_CHECK_VIN
|
||||
)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
fun showDialog() {
|
||||
if (isShowing) {
|
||||
return
|
||||
}
|
||||
show()
|
||||
}
|
||||
|
||||
fun hideDialog() {
|
||||
if (isShowing) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.mogo.och.bridge.device.checkvin
|
||||
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotCarConfigListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotCarConfigListenerManager
|
||||
import com.mogo.eagle.core.utilcode.util.ActivityUtils
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.och.common.module.biz.login.LoginStatusManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.manager.loop.BizLoopManager
|
||||
import com.mogo.och.common.module.manager.loop.LoopInfo
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
object CheckVinManager : IMoGoAutopilotCarConfigListener {
|
||||
private val TAG = CheckVinManager::class.java.simpleName
|
||||
|
||||
init {
|
||||
BizLoopManager.setLoopFunction(TAG, LoopInfo(60*5, CheckVinManager::checkVin,scheduler = Schedulers.io()))
|
||||
CallerAutopilotCarConfigListenerManager.addListener(TAG,this)
|
||||
}
|
||||
|
||||
private var checkVinErrorDialog: CheckVinErrorDialog?=null
|
||||
|
||||
override fun onAutopilotCarConfig(carConfigResp: MessagePad.CarConfigResp) {
|
||||
checkVin()
|
||||
}
|
||||
|
||||
fun getVin(): String {
|
||||
var delineVin = CallerAutoPilotControlManager.getVIN()
|
||||
if(delineVin.isEmpty()){
|
||||
delineVin = LoginStatusManager.getLoginInfo()?.vin?:""
|
||||
}
|
||||
return delineVin
|
||||
}
|
||||
|
||||
private fun checkVin() {
|
||||
LoginStatusManager.getLoginInfo()?.let {loginInfo ->
|
||||
val serverVin = loginInfo.vin
|
||||
val delineVin = CallerAutoPilotControlManager.getVIN()
|
||||
OchChainLogManager.writeChainLog(
|
||||
"checkVin",
|
||||
"5分钟检测VIN:服务器Vin:${serverVin}-----底盘Vin:${delineVin}", true,
|
||||
CheckVinErrorDialog.EVENT_KEY_INFO_CHECK_VIN
|
||||
)
|
||||
if(serverVin.isNullOrBlank()){
|
||||
return
|
||||
}
|
||||
|
||||
if(delineVin.isNullOrBlank()){
|
||||
return
|
||||
}
|
||||
|
||||
if(serverVin!=delineVin){
|
||||
val topActivity = ActivityUtils.getTopActivity()
|
||||
topActivity?.let {
|
||||
UiThreadHandler.post({
|
||||
if(checkVinErrorDialog !=null&& checkVinErrorDialog!!.isShowing){
|
||||
return@post
|
||||
}
|
||||
checkVinErrorDialog = CheckVinErrorDialog(it)
|
||||
checkVinErrorDialog?.showDialog()
|
||||
},UiThreadHandler.MODE.QUEUE)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun load() {
|
||||
OchChainLogManager.writeChainLogInit("初始化信息","初始checkVin 轮训")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.mogo.och.bridge.device.data
|
||||
|
||||
data class AirconditionStatus(
|
||||
var isOpen: Boolean,
|
||||
var pattert: Int,
|
||||
var temperature: Int,
|
||||
var windSpeed: Int
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mogo.och.bridge.device.data
|
||||
|
||||
data class DoorStatus(var isOpen: Boolean)
|
||||
|
||||
|
||||
enum class DoorPosition {
|
||||
FRONT_LEFT, FRONT_RIGHT, REAR_LEFT, REAR_RIGHT, MIDDLE
|
||||
}
|
||||
|
||||
enum class DoorState {
|
||||
OPEN,CLOSE,UNKNOWN
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.mogo.och.bridge.device.data
|
||||
|
||||
data class HeaterStatue(var isOpen: Boolean, var windSpeed: Int)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mogo.och.bridge.device.data
|
||||
|
||||
data class LightStatus(
|
||||
var isOpenLight1: Boolean,
|
||||
var isOpenLight2: Boolean,
|
||||
var isOpenatmosphere: Boolean
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.mogo.och.bridge.distance
|
||||
|
||||
data class DistanceDegree(var distance: Float, var degree: Double?, var isNext: Boolean?) :
|
||||
Comparable<DistanceDegree> {
|
||||
override fun compareTo(other: DistanceDegree): Int {
|
||||
// 对比距离
|
||||
if (distance == other.distance) {
|
||||
return 0;
|
||||
} else if (distance < other.distance) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
var next: DistanceDegree? = null
|
||||
|
||||
fun recycle() {
|
||||
synchronized(sPoolSync) {
|
||||
if (sPoolSize < MAX_POOL_SIZE) {
|
||||
next = sPool
|
||||
sPool = this
|
||||
sPoolSize++
|
||||
}
|
||||
//Logger.d("DistanceDegree","缓存对象个数${sPoolSize}个")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
var sPoolSync = Any()
|
||||
private var sPool: DistanceDegree? = null
|
||||
private var sPoolSize = 0
|
||||
private var MAX_POOL_SIZE = 20
|
||||
|
||||
|
||||
fun obtain(distance: Float, degree: Double?, isNext: Boolean?): DistanceDegree {
|
||||
synchronized(sPoolSync) {
|
||||
if (sPool != null) {
|
||||
val m: DistanceDegree = sPool!!
|
||||
sPool = m.next
|
||||
m.next = null
|
||||
m.distance = distance
|
||||
m.degree = degree
|
||||
m.isNext = isNext
|
||||
sPoolSize--
|
||||
//Logger.d("DistanceDegree","取出一个对象个数${sPoolSize}个")
|
||||
return m
|
||||
}
|
||||
//Logger.d("DistanceDegree","创建一个对象 ${sPoolSize}个")
|
||||
return DistanceDegree(distance, degree, isNext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.mogo.och.bridge.distance
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
|
||||
interface IDistanceListener {
|
||||
/**
|
||||
* @param distance 距离终点坐标的距离(终点坐标设置错误可能为负值)
|
||||
*/
|
||||
fun distanceCallback(distance: Float){}
|
||||
|
||||
/**
|
||||
* 两个站点之间的距离
|
||||
*/
|
||||
fun stationDistanceCallback(stationDistance:Float){}
|
||||
}
|
||||
|
||||
interface ITrajectoryListener{
|
||||
/**
|
||||
* @param routeArrivied 已经走过的坐标
|
||||
* @param routeArriving 没有走过的坐标
|
||||
* @param location 车的坐标
|
||||
* @return
|
||||
*/
|
||||
fun trajectoryCallback(
|
||||
routeArrivied: MutableList<MogoLocation>,
|
||||
routeArriving: MutableList<MogoLocation>,
|
||||
location: MogoLocation
|
||||
)
|
||||
}
|
||||
|
||||
interface ITrajectoryWithStationListener{
|
||||
/**
|
||||
* @param routeArrivied 已经走过的坐标 第一个是开始站点坐标
|
||||
* @param routeArriving 没有走过的坐标 最后一个是结束站点坐标
|
||||
* @param location 车的坐标
|
||||
* @return
|
||||
*/
|
||||
fun trajectoryWithStationCallback(
|
||||
routeArrivied: MutableList<MogoLocation>,
|
||||
routeArriving: MutableList<MogoLocation>,
|
||||
location: MogoLocation
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.mogo.och.bridge.distance
|
||||
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
|
||||
data class StationAndIndex(
|
||||
var stationPoint: MogoLocation?,// 站点坐标
|
||||
var index: Int?,// 坐标对应轨迹中最近的点
|
||||
var distance: Float?,//轨迹中最近的点
|
||||
var isNext:Boolean?,// 最近的点在轨迹中是在站点的下一个还是上一个
|
||||
var lineId:Long?,// 站点所属轨迹 todo 未来轨迹线路id和站点线路id 分别存储
|
||||
)
|
||||
@@ -0,0 +1,752 @@
|
||||
package com.mogo.och.bridge.distance
|
||||
|
||||
import com.mogo.commons.AbsMogoApplication
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoPlanningRottingListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListenerManager
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerPlanningRottingListenerManager
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.e
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.Companion.M_OCHCOMMON
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.LocationUtils
|
||||
import com.mogo.och.common.module.constant.OchCommonConst
|
||||
import com.mogo.och.bridge.autopilot.autopilot.OchAutopilotAnalytics
|
||||
import com.mogo.och.bridge.autopilot.location.OchLocationManager
|
||||
import com.mogo.och.bridge.autopilot.trajectory.TrajectoryCache
|
||||
import com.mogo.och.common.module.manager.loop.BizLoopManager
|
||||
import com.mogo.och.common.module.manager.loop.LoopInfo
|
||||
import com.mogo.och.bridge.utils.CoordinateCalculateRouteUtil
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
|
||||
/**
|
||||
* 计算当前位置距离站点距离和走过的和未走过的轨迹点
|
||||
*/
|
||||
object TrajectoryAndDistanceManager : IMoGoPlanningRottingListener {
|
||||
|
||||
private val distanceListeners: ConcurrentHashMap<String, IDistanceListener> =
|
||||
ConcurrentHashMap()
|
||||
private val trajectoryListeners: ConcurrentHashMap<String, ITrajectoryListener> =
|
||||
ConcurrentHashMap()
|
||||
private val trajectoryWithStationListeners: ConcurrentHashMap<String, ITrajectoryWithStationListener> =
|
||||
ConcurrentHashMap()
|
||||
|
||||
private const val TAG = "DistanceManager"
|
||||
private const val DISTANCE = "BusPassengerModelDistance"
|
||||
|
||||
const val errorTypeNoneLineId = "起始站点值异常,请重新选择此任务执行并上报问题"
|
||||
|
||||
|
||||
fun addDistanceListener(tag: String, listener: IDistanceListener) {
|
||||
if (distanceListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
distanceListeners[tag] = listener
|
||||
}
|
||||
|
||||
fun addTrajectoryListener(tag: String, listener: ITrajectoryListener) {
|
||||
if (trajectoryListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
trajectoryListeners[tag] = listener
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun addTrajectoryWithStationListener(tag: String, listener: ITrajectoryWithStationListener) {
|
||||
if (trajectoryWithStationListeners.containsKey(tag)) {
|
||||
return
|
||||
}
|
||||
trajectoryWithStationListeners[tag] = listener
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除监听
|
||||
* @param tag 标记,用来注销监听使用
|
||||
*/
|
||||
fun removeListener(tag: String) {
|
||||
distanceListeners.remove(tag)
|
||||
trajectoryListeners.remove(tag)
|
||||
trajectoryWithStationListeners.remove(tag)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 所有轨迹点
|
||||
*/
|
||||
@Volatile
|
||||
private var mRoutePoints: MutableList<MogoLocation>? = ArrayList()
|
||||
|
||||
/**
|
||||
* 0-1 1-2 2-3 各个轨迹点的距离
|
||||
*/
|
||||
@Volatile
|
||||
private var mRoutePointsDistance: MutableList<Float>? = ArrayList()
|
||||
|
||||
/**
|
||||
* 所有轨迹点距离的和
|
||||
*/
|
||||
@Volatile
|
||||
private var maxDistanceAllPoint: Double = 0.0
|
||||
|
||||
/**
|
||||
* 线路Id
|
||||
*/
|
||||
@Volatile
|
||||
private var lineId: Long? = null
|
||||
|
||||
/**
|
||||
* 结束站点
|
||||
*/
|
||||
@Volatile
|
||||
private var endStationInfo: StationAndIndex = StationAndIndex(null, null, null, null, null)
|
||||
|
||||
/**
|
||||
* 开始站点
|
||||
*/
|
||||
@Volatile
|
||||
private var startStationInfo: StationAndIndex = StationAndIndex(null, null, null, null, null)
|
||||
|
||||
/**
|
||||
* startStationInfo endStationInfo 站点之间的距离
|
||||
*/
|
||||
private val stationDistance: ConcurrentHashMap<String, Float> = ConcurrentHashMap()
|
||||
|
||||
/**
|
||||
* 上一次(上一个tick)计算最近点的缓存
|
||||
*/
|
||||
private var preCarLocationIndexInTrajectory = 0
|
||||
|
||||
init {
|
||||
CallerPlanningRottingListenerManager.addListener(TAG, this)
|
||||
}
|
||||
|
||||
override fun onAutopilotRotting(globalPathResp: MessagePad.GlobalPathResp?) {
|
||||
d(M_OCHCOMMON + TAG, "onAutopilotRotting: 收到轨迹")
|
||||
globalPathResp?.wayPointsList?.let {
|
||||
if (it.size > 0) {
|
||||
d(
|
||||
M_OCHCOMMON + TAG,
|
||||
"收到轨迹:轨迹个数${it.size}第一个点${it[0]}最后一个点:${it.last()} 轨迹id:${globalPathResp.lineId}"
|
||||
)
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (globalPathResp.lineId != null) {// 适配低版本不传递lineId
|
||||
if (globalPathResp.lineId == lineId && !mRoutePoints.isNullOrEmpty()) {
|
||||
d(M_OCHCOMMON + TAG, "重复轨迹")
|
||||
startCalculateDistanceLoop()
|
||||
return
|
||||
}else{
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
}
|
||||
this.lineId = globalPathResp.lineId
|
||||
}
|
||||
endCalculateDistanceLoop()
|
||||
updateRoutePoints(it)
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateRoutePoints(routePoints: List<MessagePad.Location>?) {
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
val latLngModels = CoordinateCalculateRouteUtil
|
||||
.coordinateConverterWgsToGcjLocations(AbsMogoApplication.getApp(), routePoints!!)
|
||||
mRoutePoints = latLngModels
|
||||
TrajectoryCache.writeLastTrajectory2jsonFile(latLngModels, lineId.toString())
|
||||
|
||||
mRoutePointsDistance = ArrayList()
|
||||
maxDistanceAllPoint = 0.0
|
||||
mRoutePoints?.forEachIndexed { index, current ->
|
||||
if (mRoutePoints!!.last() != current) {
|
||||
val next = mRoutePoints!![index + 1]
|
||||
val distanceItem = CoordinateUtils.calculateLineDistance(
|
||||
current.longitude,
|
||||
current.latitude,
|
||||
next.longitude,
|
||||
next.latitude
|
||||
)
|
||||
mRoutePointsDistance?.add(distanceItem)
|
||||
maxDistanceAllPoint += distanceItem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置或清理站点坐标
|
||||
*/
|
||||
fun setStationPoint(
|
||||
startStationInfo: MogoLocation?,
|
||||
endStationInfo: MogoLocation?,
|
||||
lineId: Long?
|
||||
) {
|
||||
d(
|
||||
M_OCHCOMMON + TAG,
|
||||
"线路id:${lineId}设置站点:开始站点${startStationInfo}、结束站点:${endStationInfo}"
|
||||
)
|
||||
if (startStationInfo == null || endStationInfo == null || lineId == -1L) {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
endCalculateDistanceLoop()
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
this.endStationInfo.stationPoint = null
|
||||
this.startStationInfo.stationPoint = null
|
||||
this.lineId = null
|
||||
stationDistance.clear()
|
||||
} else {
|
||||
if (isSameStation(this.startStationInfo.stationPoint, startStationInfo) &&
|
||||
isSameStation(this.endStationInfo.stationPoint, endStationInfo)
|
||||
) {
|
||||
if (this.lineId != lineId) {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
stationDistance.clear()
|
||||
}
|
||||
} else {
|
||||
this.endStationInfo.index = null
|
||||
this.endStationInfo.distance = null
|
||||
this.endStationInfo.isNext = null
|
||||
this.endStationInfo.lineId = null
|
||||
this.startStationInfo.index = null
|
||||
this.startStationInfo.distance = null
|
||||
this.startStationInfo.isNext = null
|
||||
this.startStationInfo.lineId = null
|
||||
if (this.lineId == 0L || this.lineId == null) {
|
||||
// 兼容老MAP 不返回轨迹id lineID
|
||||
} else {
|
||||
if (this.lineId != lineId) {// bus 切换站点不会切线路
|
||||
mRoutePoints = null
|
||||
mRoutePointsDistance = null
|
||||
TrajectoryCache.deleteCatcheFile()
|
||||
}
|
||||
}
|
||||
stationDistance.clear()
|
||||
}
|
||||
this.endStationInfo.stationPoint = endStationInfo
|
||||
this.startStationInfo.stationPoint = startStationInfo
|
||||
this.lineId = lineId
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSameStation(stationOne: MogoLocation?, stationTwo: MogoLocation?): Boolean {
|
||||
if (stationOne == null || stationTwo == null) {
|
||||
return false
|
||||
}
|
||||
if (stationOne.longitude == stationTwo.longitude && stationOne.latitude == stationTwo.latitude) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据两点距离和轨迹距离来计算真实距离
|
||||
*/
|
||||
private fun calculateDistance() {
|
||||
//mLocation gcj坐标
|
||||
OchLocationManager.getGCJ02Location().let {
|
||||
if (mRoutePoints.isNullOrEmpty() || endStationInfo.stationPoint == null) {
|
||||
d(M_OCHCOMMON + TAG, "没有轨迹或站点坐标停止计算")
|
||||
//结束距离计算
|
||||
endCalculateDistanceLoop()
|
||||
return
|
||||
}
|
||||
if (it.latitude == 0.0 && it.longitude == 0.0) {
|
||||
return
|
||||
}
|
||||
calculateRouteSumLength(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停路距计算
|
||||
*/
|
||||
fun suspendCalculate() {
|
||||
endCalculateDistanceLoop()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun reStartCalculate() {
|
||||
startCalculateDistanceLoop()
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动路距计算
|
||||
*/
|
||||
private fun startCalculateDistanceLoop() {
|
||||
BizLoopManager.setLoopFunction(
|
||||
DISTANCE,
|
||||
LoopInfo(
|
||||
1,
|
||||
::calculateDistance,
|
||||
scheduler = Schedulers.computation()
|
||||
)
|
||||
)
|
||||
d(M_OCHCOMMON + TAG, "开始路距计算")
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束启动路距计算
|
||||
*/
|
||||
private fun endCalculateDistanceLoop() {
|
||||
BizLoopManager.removeLoopFunction(DISTANCE)
|
||||
d(M_OCHCOMMON + TAG, "结束路距计算")
|
||||
}
|
||||
|
||||
|
||||
@Synchronized
|
||||
fun calculateRouteSumLength(
|
||||
location: MogoLocation,
|
||||
) {
|
||||
val autoPilotState = CallerAutoPilotStatusListenerManager.getAutoPilotStatusInfo().state
|
||||
val locationInfo =
|
||||
"自动驾驶状态:$autoPilotState line信息:${lineId}定位信息:${location.latitude},${location.longitude},${location.heading} 当前速度:${location.gnssSpeed}"
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
// 计算起始站点在轨迹中的信息 这个是一个常量
|
||||
if (startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext == null
|
||||
&& startStationInfo.index == null
|
||||
&& startStationInfo.distance == null
|
||||
) {
|
||||
//要前往的站在轨迹中对应的点的信息
|
||||
val startStationInfo = CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
mRoutePoints!!.size,
|
||||
mRoutePoints!!,
|
||||
startStationInfo.stationPoint!!,
|
||||
1,
|
||||
useHeading = false
|
||||
)
|
||||
this.startStationInfo.isNext = startStationInfo.second
|
||||
this.startStationInfo.index = startStationInfo.first
|
||||
this.startStationInfo.distance = startStationInfo.third
|
||||
preCarLocationIndexInTrajectory = startStationInfo.first
|
||||
val calculateData =
|
||||
"距离起始站点最近的点:${startStationInfo.first} 点在站的后面:${startStationInfo.second} 距离点的距离:${startStationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
}
|
||||
|
||||
// 计算结束站点在轨迹中的信息 这个是一个常量可以缓存
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext == null
|
||||
&& endStationInfo.index == null
|
||||
&& endStationInfo.distance == null
|
||||
) {
|
||||
//要前往的站在轨迹中对应的点
|
||||
val endStationInfo = CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
mRoutePoints!!.size,
|
||||
mRoutePoints!!,
|
||||
endStationInfo.stationPoint!!,
|
||||
3,
|
||||
useHeading = false
|
||||
)
|
||||
this.endStationInfo.isNext = endStationInfo.second
|
||||
this.endStationInfo.index = endStationInfo.first
|
||||
this.endStationInfo.distance = endStationInfo.third
|
||||
val calculateData =
|
||||
"距离结束站点最近的点:${endStationInfo.first} 点在站的后面:${endStationInfo.second} 距离点的距离:${endStationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
}
|
||||
|
||||
try {
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext != null
|
||||
&& endStationInfo.index != null
|
||||
&& endStationInfo.distance != null
|
||||
&& startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext != null
|
||||
&& startStationInfo.index != null
|
||||
&& startStationInfo.distance != null
|
||||
) {
|
||||
calculateStationDistance()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "计算两个站点间的距离")
|
||||
}
|
||||
|
||||
val carLocationInfo: Triple<Int, Boolean?, Float> = if (endStationInfo.isNext == true) {
|
||||
// 计算车的位置在轨迹中的信息 这个是一个变量可以缓存
|
||||
CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory, endStationInfo.index!!, mRoutePoints!!, location, 2
|
||||
)
|
||||
} else {
|
||||
CoordinateCalculateRouteUtil.getNearestPointInfo(
|
||||
preCarLocationIndexInTrajectory,
|
||||
endStationInfo.index!! + 1,
|
||||
mRoutePoints!!,
|
||||
location,
|
||||
2
|
||||
)
|
||||
}
|
||||
val calculateData =
|
||||
"距离轨迹点最近的点:${carLocationInfo.first} 点在站的后面:${carLocationInfo.second} 距离点的距离:${carLocationInfo.third}"
|
||||
writeLog(calculateData, locationInfo)
|
||||
if (carLocationInfo.second == null || carLocationInfo.third > 1_000) {
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
return
|
||||
}
|
||||
|
||||
var maxDisatance = 0.0f
|
||||
if (carLocationInfo.second == true) {
|
||||
if (carLocationInfo.first > 0) {
|
||||
maxDisatance = mRoutePointsDistance?.get(carLocationInfo.first - 1) ?: 0f
|
||||
}
|
||||
} else {
|
||||
maxDisatance = mRoutePointsDistance?.get(carLocationInfo.first) ?: 0f
|
||||
}
|
||||
if (carLocationInfo.third > maxDisatance) {
|
||||
preCarLocationIndexInTrajectory = 0
|
||||
writeLog("到点的距离${carLocationInfo.third},最大距离${maxDisatance}", locationInfo)
|
||||
return
|
||||
}
|
||||
|
||||
preCarLocationIndexInTrajectory = carLocationInfo.first
|
||||
|
||||
// 距离回调
|
||||
try {
|
||||
if (distanceListeners.size > 0) {
|
||||
invokeDistance(carLocationInfo, location, locationInfo)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "距离计算错误")
|
||||
}
|
||||
// 不带站点轨迹回调
|
||||
try {
|
||||
if (trajectoryListeners.size > 0) {
|
||||
invokeTrajectory(carLocationInfo, location)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "轨迹线(轨迹两头)计算错误")
|
||||
}
|
||||
|
||||
// 只展示站点之间轨迹
|
||||
try {
|
||||
if (trajectoryWithStationListeners.size > 0) {
|
||||
invokeTrajectoryWithStation(carLocationInfo, location)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e(M_OCHCOMMON + TAG, "轨迹线(站点两头)计算错误")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点间距离
|
||||
*/
|
||||
private fun calculateStationDistance() {
|
||||
var lastSumLength: Float
|
||||
val key = getKey()
|
||||
if (stationDistance[key] != null) {
|
||||
return
|
||||
}
|
||||
|
||||
val stationIndex = endStationInfo.index ?: 0
|
||||
if (startStationInfo.index!! < stationIndex - 1) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints!!.subList(startStationInfo.index!!, stationIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = CoordinateCalculateRouteUtil.calculateRouteSumLength(subList)
|
||||
val stationDistance = endStationInfo.distance ?: 0f
|
||||
if (endStationInfo.isNext == true) {// isNext = true
|
||||
lastSumLength -= stationDistance
|
||||
} else {// isNext = false
|
||||
lastSumLength += stationDistance
|
||||
}
|
||||
if (startStationInfo.isNext == true) {// 是否是下一个 true 下一个
|
||||
lastSumLength += startStationInfo.distance!!
|
||||
} else {
|
||||
lastSumLength -= startStationInfo.distance!!
|
||||
}
|
||||
} else {
|
||||
val lastPoints = endStationInfo.stationPoint
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
startStationInfo.stationPoint!!.longitude, startStationInfo.stationPoint!!.latitude,
|
||||
lastPoints!!.longitude, lastPoints.latitude
|
||||
)
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "两站点距离:$lastSumLength")
|
||||
stationDistance[key] = lastSumLength
|
||||
|
||||
if (distanceListeners.size > 0) {
|
||||
distanceListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.stationDistanceCallback(lastSumLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKey(): String {
|
||||
return "${startStationInfo.stationPoint!!.longitude}${startStationInfo.stationPoint!!.latitude}${endStationInfo.stationPoint!!.longitude}${endStationInfo.stationPoint!!.latitude}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 到结束站点的距离 站点设置错误可能为负值
|
||||
*/
|
||||
private fun invokeDistance(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation,
|
||||
locationInfo: String
|
||||
) {
|
||||
var lastSumLength: Float
|
||||
|
||||
val stationIndex = endStationInfo.index ?: 0
|
||||
if (carLocationInfo.first < stationIndex - 1) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints!!.subList(carLocationInfo.first, stationIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = CoordinateCalculateRouteUtil.calculateRouteSumLength(subList)
|
||||
val stationDistance = endStationInfo.distance ?: 0f
|
||||
if (endStationInfo.isNext == true) {// isNext = true
|
||||
lastSumLength -= stationDistance
|
||||
} else {// isNext = false
|
||||
lastSumLength += stationDistance
|
||||
}
|
||||
if (carLocationInfo.second == true) {// 是否是下一个 true 下一个
|
||||
lastSumLength += carLocationInfo.third
|
||||
} else {
|
||||
lastSumLength -= carLocationInfo.third
|
||||
}
|
||||
} else {
|
||||
val lastPoints = endStationInfo.stationPoint
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
lastPoints!!.longitude, lastPoints.latitude,
|
||||
location.longitude, location.latitude
|
||||
)
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "距离终点:$lastSumLength")
|
||||
if (lastSumLength > maxDistanceAllPoint) {
|
||||
// 大于最大值需要需要删除此次计算
|
||||
writeLog("距离终点:$lastSumLength", locationInfo)
|
||||
return
|
||||
}
|
||||
if (distanceListeners.size > 0) {
|
||||
distanceListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.distanceCallback(lastSumLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点之间的轨迹(从轨迹起点算起到轨迹结束点结束)
|
||||
* routeArrivied 已经走过的轨迹点
|
||||
* routeArriving 还没有走过的轨迹
|
||||
* location 车的轨迹点
|
||||
*/
|
||||
private fun invokeTrajectory(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation
|
||||
) {
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
val routeArrivied = mutableListOf<MogoLocation>()
|
||||
val routeArriving = mutableListOf<MogoLocation>()
|
||||
if (carLocationInfo.second == true) {// isNext = true
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(0, carLocationInfo.first))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(carLocationInfo.first, mRoutePoints!!.size))
|
||||
} else {// isNext = false
|
||||
val indexNext = carLocationInfo.first + 1
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(0, indexNext))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(indexNext, mRoutePoints!!.size))
|
||||
}
|
||||
if (trajectoryListeners.size > 0) {
|
||||
trajectoryListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.trajectoryCallback(routeArrivied, routeArriving, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算站点之间的轨迹(从开始站点算起到结束站点)
|
||||
* routeArrivied 已经走过的轨迹点
|
||||
* routeArriving 还没有走过的轨迹
|
||||
* location 车的轨迹点
|
||||
*/
|
||||
private fun invokeTrajectoryWithStation(
|
||||
carLocationInfo: Triple<Int, Boolean?, Float>,
|
||||
location: MogoLocation
|
||||
) {
|
||||
if (mRoutePoints.isNullOrEmpty()) return
|
||||
val routeArrivied = mutableListOf<MogoLocation>()
|
||||
val routeArriving = mutableListOf<MogoLocation>()
|
||||
var fromCut = 0
|
||||
var endCut = mRoutePoints!!.size
|
||||
if (startStationInfo.stationPoint != null
|
||||
&& startStationInfo.isNext != null
|
||||
&& startStationInfo.index != null
|
||||
&& startStationInfo.distance != null
|
||||
) {
|
||||
if (startStationInfo.isNext == true) {
|
||||
fromCut = startStationInfo.index!!
|
||||
} else {
|
||||
fromCut = startStationInfo.index!! + 1
|
||||
}
|
||||
}
|
||||
|
||||
if (endStationInfo.stationPoint != null
|
||||
&& endStationInfo.isNext != null
|
||||
&& endStationInfo.index != null
|
||||
&& endStationInfo.distance != null
|
||||
) {
|
||||
if (endStationInfo.isNext == true) {
|
||||
endCut = endStationInfo.index!!
|
||||
} else {
|
||||
endCut = endStationInfo.index!! + 1
|
||||
}
|
||||
}
|
||||
d(M_OCHCOMMON + TAG, "根据站点切个:第一个点:$fromCut 最后一个点$endCut")
|
||||
if (carLocationInfo.second == true) {// isNext = true
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(fromCut, carLocationInfo.first))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(carLocationInfo.first, endCut))
|
||||
} else {// isNext = false
|
||||
val indexNext = carLocationInfo.first + 1
|
||||
routeArrivied.addAll(mRoutePoints!!.subList(fromCut, indexNext))
|
||||
routeArriving.addAll(mRoutePoints!!.subList(indexNext, endCut))
|
||||
}
|
||||
|
||||
routeArrivied.add(0, startStationInfo.stationPoint!!)
|
||||
routeArriving.add(endStationInfo.stationPoint!!)
|
||||
if (trajectoryWithStationListeners.size > 0) {
|
||||
trajectoryWithStationListeners.forEach {
|
||||
//val tag = it.key
|
||||
val listener = it.value
|
||||
listener.trajectoryWithStationCallback(routeArrivied, routeArriving, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @ChainLog(
|
||||
// linkChainLog = ChainConstant.CHAIN_TYPE_OCH,
|
||||
// linkCode = ChainConstant.CHAIN_SOURCE_OCH,
|
||||
// nodeAliasCode = ChainConstant.CHAIN_CODE_OCH_COMMON_DISTANCE,
|
||||
// paramIndexes = [0,1]
|
||||
// )
|
||||
private fun writeLog(carLocationInfo: String, location: String) {
|
||||
d(M_OCHCOMMON + TAG, carLocationInfo)
|
||||
d(M_OCHCOMMON + TAG, location)
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回空为可启动自驾
|
||||
* 返回其他不可启动自驾 返回为原因
|
||||
*/
|
||||
fun canStartAutopilot(lineId: Number?): String {
|
||||
if (lineId == null) {
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("未传轨迹ID")
|
||||
return "请确认线路ID"
|
||||
}
|
||||
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("条件记录:lineId:${lineId}----this.lineId:${this.lineId}、mRoutePoints情况:${mRoutePoints?.size}")
|
||||
|
||||
try {
|
||||
if (mRoutePoints.isNullOrEmpty()) {
|
||||
// 判断距离起始站的距离
|
||||
// 没有收到过轨迹
|
||||
// 收到过轨迹 且底盘没有在自动驾驶中(没办法申请轨迹) 自驾中重启底盘的形式
|
||||
val redCatche = TrajectoryCache.redCatche(lineId.toString())
|
||||
return if (redCatche.isNullOrEmpty()) {
|
||||
distanceWithStartStation()
|
||||
} else {
|
||||
val currentPoint = OchLocationManager.getGCJ02Location()
|
||||
distanceWithTrajectory(redCatche,currentPoint)
|
||||
}
|
||||
|
||||
} else {
|
||||
return if (this.lineId == 0L || this.lineId == null) {
|
||||
val currentPoint = OchLocationManager.getGCJ02Location()
|
||||
distanceWithTrajectory(mRoutePoints!!,currentPoint)
|
||||
} else {
|
||||
if (lineId.toLong() != this.lineId) {
|
||||
// 判断距离起始站的距离
|
||||
distanceWithStartStation()
|
||||
} else {
|
||||
val currentPoint = OchLocationManager.getGCJ02Location()
|
||||
distanceWithTrajectory(mRoutePoints!!,currentPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("距离站点距离:不支持的条件直接放过")
|
||||
return ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 距离站点的距离
|
||||
*/
|
||||
private fun distanceWithStartStation(): String {
|
||||
if (startStationInfo.stationPoint == null) {
|
||||
return errorTypeNoneLineId
|
||||
}
|
||||
val currentPoint = OchLocationManager.getGCJ02Location()
|
||||
val distance = CoordinateUtils.calculateLineDistance(
|
||||
currentPoint.longitude,
|
||||
currentPoint.latitude,
|
||||
startStationInfo.stationPoint!!.longitude,
|
||||
startStationInfo.stationPoint!!.latitude
|
||||
)
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("距离站点距离:${distance}")
|
||||
return if (distance <= OchCommonConst.AUTOMATIC_PLANNING_MAX_DISTANCE) {
|
||||
""
|
||||
} else {
|
||||
"距离起始站点超过15米"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 距离轨迹的距离
|
||||
*/
|
||||
fun distanceWithTrajectory(redCatche: MutableList<MogoLocation>,currentPoint:MogoLocation): String {
|
||||
redCatche.forEachIndexed { index, mogoLocation ->
|
||||
if(index!=0){
|
||||
val prePoint = redCatche.get(index - 1)
|
||||
val pointToLine = LocationUtils.pointToLine(
|
||||
prePoint.longitude,
|
||||
prePoint.latitude,
|
||||
mogoLocation.longitude,
|
||||
mogoLocation.latitude,
|
||||
currentPoint.longitude,
|
||||
currentPoint.latitude
|
||||
)
|
||||
if(pointToLine<=OchCommonConst.AUTOMATIC_PLANNING_MAX_DISTANCE){
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("距离轨迹线距离:${pointToLine}")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
OchAutopilotAnalytics.triggerDistance2LineorStation("距离轨迹线超过15m,无法启动自驾")
|
||||
return "距离轨迹线超过15米"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.mogo.och.bridge.ui.autopilot
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.animation.LinearInterpolator
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.findViewTreeViewModelStoreOwner
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.och.bridge.R
|
||||
import com.mogo.och.bridge.autopilot.autopilot.IOchAutopilotStatusListener
|
||||
import com.mogo.och.common.module.utils.BigFrameAnimatorContainer
|
||||
import com.mogo.och.common.module.utils.ResourcesUtils
|
||||
import kotlinx.android.synthetic.main.common_autopilot_view.view.aciv_autopilot_running_ani
|
||||
import kotlinx.android.synthetic.main.common_autopilot_view.view.aciv_autopilot_state
|
||||
import kotlinx.android.synthetic.main.common_autopilot_view.view.actv_autopilot_head
|
||||
import kotlinx.android.synthetic.main.common_autopilot_view.view.actv_autopilot_state
|
||||
import kotlinx.android.synthetic.main.common_autopilot_view.view.actv_pxjs_state
|
||||
|
||||
class AutopilotState @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : ConstraintLayout(context, attrs, defStyleAttr), IOchAutopilotStatusListener,
|
||||
AutopilotStateModel.AutopilotStateCallback {
|
||||
|
||||
private val TAG = "AutopilotState"
|
||||
|
||||
private var viewModel:AutopilotStateModel?=null
|
||||
|
||||
private var autopilotStateAnimator: BigFrameAnimatorContainer?=null
|
||||
|
||||
private lateinit var autopilotLoadingAnimator: ObjectAnimator
|
||||
private lateinit var autopilotChangeStateAnimator: ObjectAnimator
|
||||
|
||||
private fun initView() {
|
||||
LayoutInflater.from(context).inflate(R.layout.common_autopilot_view, this, true)
|
||||
autopilotStateAnimator = BigFrameAnimatorContainer(R.array.in_auto, 31, aciv_autopilot_running_ani)
|
||||
autopilotLoadingAnimator = ObjectAnimator.ofFloat(aciv_autopilot_state, "rotation", 0f, 360f);
|
||||
autopilotLoadingAnimator.interpolator = LinearInterpolator()
|
||||
autopilotLoadingAnimator.repeatCount = -1 //无限循环
|
||||
autopilotLoadingAnimator.duration = 2000 //无限循环
|
||||
|
||||
autopilotChangeStateAnimator = ObjectAnimator.ofFloat(aciv_autopilot_state, "alpha", 1f, 0f,1f);
|
||||
autopilotChangeStateAnimator.interpolator = LinearInterpolator()
|
||||
autopilotChangeStateAnimator.duration = 300
|
||||
onClick {
|
||||
startAutopilot()
|
||||
}
|
||||
}
|
||||
|
||||
fun startAutopilot(){
|
||||
viewModel?.startAutopilot()
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
viewModel = findViewTreeViewModelStoreOwner()?.let {
|
||||
ViewModelProvider(it).get(AutopilotStateModel::class.java)
|
||||
}
|
||||
viewModel?.setViewCallback(this)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
autopilotStateAnimator?.release()
|
||||
}
|
||||
|
||||
|
||||
|
||||
init {
|
||||
try {
|
||||
initView()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun startAutopilotAnimation() {
|
||||
CallerLogger.d(TAG,"播放启动自驾动画")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_starting_new)
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_starting)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
autopilotLoadingAnimator.start()
|
||||
|
||||
val animatorSet = AnimatorSet()
|
||||
animatorSet.playTogether(autopilotChangeStateAnimator, autopilotLoadingAnimator)
|
||||
animatorSet.start()
|
||||
}
|
||||
|
||||
override fun stopAutopilotAnimation() {
|
||||
CallerLogger.d(TAG,"结束启动自驾动画")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_enable)
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_starting)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
override fun inAutopilot() {
|
||||
CallerLogger.d(TAG,"展示自驾中UI")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_running)
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_running)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
aciv_autopilot_running_ani.visibility = VISIBLE
|
||||
autopilotStateAnimator?.start()
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
override fun autopilotDisable() {
|
||||
CallerLogger.d(TAG,"不可启动自驾")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_unenable)
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_start)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
aciv_autopilot_running_ani.visibility = GONE
|
||||
autopilotStateAnimator?.stop()
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
override fun canStartAutopilot() {
|
||||
CallerLogger.d(TAG,"可以启动自驾")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_enable)
|
||||
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_start)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = true
|
||||
|
||||
aciv_autopilot_running_ani.visibility = GONE
|
||||
autopilotStateAnimator?.stop()
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
override fun inRemoteDriver() {
|
||||
CallerLogger.d(TAG,"展示平行驾驶中UI")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_running)
|
||||
|
||||
actv_pxjs_state.visibility = VISIBLE
|
||||
actv_autopilot_head.visibility = GONE
|
||||
actv_autopilot_state.visibility = GONE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_start)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
aciv_autopilot_running_ani.visibility = VISIBLE
|
||||
autopilotStateAnimator?.start()
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
override fun startAutopilotSuccess() {
|
||||
|
||||
}
|
||||
|
||||
override fun startAutopilotFail() {
|
||||
CallerLogger.d(TAG,"启动自动驾驶失败")
|
||||
updateImageInAnimator(R.drawable.common_autopilot_fail)
|
||||
|
||||
actv_pxjs_state.visibility = GONE
|
||||
actv_autopilot_head.visibility = VISIBLE
|
||||
actv_autopilot_state.visibility = VISIBLE
|
||||
|
||||
actv_autopilot_head.setTextColor(ResourcesUtils.getColor(R.color.common_B3FFFFFF))
|
||||
actv_autopilot_state.setTextColor(ResourcesUtils.getColor(R.color.common_FF4E41))
|
||||
actv_autopilot_state.text = ResourcesUtils.getString(R.string.common_autopilot_fail)
|
||||
actv_pxjs_state.setTextColor(ResourcesUtils.getColor(R.color.common_19FFCB))
|
||||
AutopilotState@this.isEnabled = false
|
||||
|
||||
aciv_autopilot_running_ani.visibility = GONE
|
||||
autopilotStateAnimator?.stop()
|
||||
autopilotLoadingAnimator.cancel()
|
||||
autopilotChangeStateAnimator.start()
|
||||
}
|
||||
|
||||
private fun updateImageInAnimator(@DrawableRes resource:Int){
|
||||
UiThreadHandler.postDelayed({
|
||||
aciv_autopilot_state.setImageResource(resource)
|
||||
},150,UiThreadHandler.MODE.QUEUE)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package com.mogo.och.bridge.ui.autopilot
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotControlManager
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.och.common.module.debug.autopilot.AutopilotStateDebug
|
||||
import com.mogo.och.common.module.debug.autopilot.IOchDebugAutopilotStatusListener
|
||||
import com.mogo.och.bridge.autopilot.autopilot.IOchAutopilotStatusListener
|
||||
import com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager
|
||||
import com.mogo.och.bridge.autopilot.line.ILineCallback
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
import com.mogo.och.common.module.manager.logchainanalytic.OchChainLogManager
|
||||
import com.mogo.och.common.module.manager.loop.BizLoopManager
|
||||
import com.mogo.och.common.module.utils.RxUtils
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
/**
|
||||
* @author XuXinChao
|
||||
* @description BadCase录包管理页面
|
||||
* @since: 2022/12/15
|
||||
*/
|
||||
class AutopilotStateModel : ViewModel(),
|
||||
com.mogo.och.bridge.autopilot.autopilot.IOchAutopilotStatusListener,
|
||||
com.mogo.och.bridge.autopilot.line.ILineCallback,
|
||||
IOchDebugAutopilotStatusListener {
|
||||
|
||||
private val TAG = AutopilotStateModel::class.java.simpleName
|
||||
|
||||
private var viewCallback: AutopilotStateCallback?=null
|
||||
|
||||
private val isPalyStartAni = AtomicBoolean(false)
|
||||
|
||||
|
||||
override fun onCleared() {
|
||||
this.viewCallback = null
|
||||
AutopilotStateDebug.removeListener(TAG)
|
||||
com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.removeListener(TAG)
|
||||
com.mogo.och.bridge.autopilot.line.LineManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
fun setViewCallback(viewCallback: AutopilotStateCallback){
|
||||
this.viewCallback = viewCallback
|
||||
AutopilotStateDebug.addListener(TAG,this)
|
||||
com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.addListener(TAG,this)
|
||||
com.mogo.och.bridge.autopilot.line.LineManager.addListener(TAG,this)
|
||||
}
|
||||
|
||||
override fun debugStatusChange(debugStatus: Boolean) {
|
||||
super.debugStatusChange(debugStatus)
|
||||
if(debugStatus){
|
||||
com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.removeListener(TAG)
|
||||
com.mogo.och.bridge.autopilot.line.LineManager.removeListener(TAG)
|
||||
}else{
|
||||
com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.addListener(TAG,this)
|
||||
com.mogo.och.bridge.autopilot.line.LineManager.addListener(TAG,this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun debugDispatchState(state: Int?) {
|
||||
super.debugDispatchState(state)
|
||||
when (state) {
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE-> {// 不可用 不可启动自驾
|
||||
this.viewCallback?.autopilotDisable()
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE-> {
|
||||
this.viewCallback?.canStartAutopilot()
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING-> {// 自驾中
|
||||
this.viewCallback?.stopAutopilotAnimation()
|
||||
this.viewCallback?.inAutopilot()
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING-> {// 平行驾驶中
|
||||
this.viewCallback?.stopAutopilotAnimation()
|
||||
this.viewCallback?.inRemoteDriver()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotStatusResponse(state: Int) {
|
||||
OchChainLogManager.writeChainLog("自驾信息","自驾状态变化:${state}")
|
||||
autopilotStateChange()
|
||||
}
|
||||
|
||||
override fun canStartAutopilot(canStart: Boolean) {
|
||||
OchChainLogManager.writeChainLog("自驾信息","能否启动自驾:${canStart}")
|
||||
autopilotStateChange()
|
||||
}
|
||||
|
||||
override fun onFsmCanStartAutopilot(can: Boolean) {
|
||||
OchChainLogManager.writeChainLog("自驾信息","FSM能否启动自驾:${can}")
|
||||
autopilotStateChange()
|
||||
}
|
||||
|
||||
private fun autopilotStateChange(){
|
||||
// 正在起自驾过程中
|
||||
// 自驾状态变化为非自驾状态
|
||||
// 或者
|
||||
// FSM 状态改为不能启动自驾
|
||||
// 按照启动自驾失败计算
|
||||
if(isPalyStartAni.get() &&
|
||||
(!CallerAutoPilotControlManager.isCanStartAutopilot(false)
|
||||
|| com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.autopilotState!=IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING)){
|
||||
OchChainLogManager.writeChainLog("自驾信息","正在起自驾过程中、自驾状态变化切为非自驾状态或者FSM 状态改为不能启动自驾")
|
||||
startAutopilotFail()
|
||||
return
|
||||
}
|
||||
BizLoopManager.runInMainThread{
|
||||
OchChainLogManager.writeChainLog("自驾信息","自驾状态:${com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.autopilotState} 能否启动自驾:${CallerAutoPilotControlManager.isCanStartAutopilot(false)}")
|
||||
when (com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.autopilotState) {
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_DISABLE-> {// 不可用 不可启动自驾
|
||||
this.viewCallback?.autopilotDisable()
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_ENABLE-> {
|
||||
if (CallerAutoPilotControlManager.isCanStartAutopilot(false) && com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.canStartAutopilotFromFSM) {// 不可用
|
||||
this.viewCallback?.canStartAutopilot()
|
||||
} else {// 部分可用
|
||||
this.viewCallback?.autopilotDisable()
|
||||
}
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING-> {// 自驾中
|
||||
this.viewCallback?.stopAutopilotAnimation()
|
||||
this.viewCallback?.inAutopilot()
|
||||
}
|
||||
IMoGoAutopilotStatusListener.STATUS_PARALLEL_DRIVING-> {// 平行驾驶中
|
||||
this.viewCallback?.stopAutopilotAnimation()
|
||||
this.viewCallback?.inRemoteDriver()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun startAutopilot() {
|
||||
OchChainLogManager.writeChainLog("自驾信息","启动自驾")
|
||||
if(AutopilotStateDebug.debugStatus){
|
||||
sendStartAutopilotSuccess()
|
||||
RxUtils.createSubscribe(5_000) {
|
||||
startAutopilotFail()
|
||||
}
|
||||
}else {
|
||||
com.mogo.och.bridge.autopilot.line.LineManager.startAutopilot()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件过滤完成 正式进入启动自驾状态
|
||||
*/
|
||||
override fun sendStartAutopilotSuccess() {
|
||||
OchChainLogManager.writeChainLog("自驾信息","启动自驾成功")
|
||||
BizLoopManager.runInMainThread {
|
||||
this.viewCallback?.startAutopilotAnimation()
|
||||
isPalyStartAni.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun startAutopilotTimeOut() {
|
||||
OchChainLogManager.writeChainLog("自驾信息","启动自驾超时失败")
|
||||
if(com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.autopilotState == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){
|
||||
autopilotStateChange()
|
||||
}else {
|
||||
startAutopilotFail()
|
||||
}
|
||||
}
|
||||
|
||||
override fun startAutopilotFailure(startFailedCode: String?, startFailedMessage: String?) {
|
||||
OchChainLogManager.writeChainLog("自驾信息","底盘强制失败原因:${startFailedCode}_${startFailedMessage}")
|
||||
if(com.mogo.och.bridge.autopilot.autopilot.OchAutoPilotStatusListenerManager.autopilotState == IMoGoAutopilotStatusListener.STATUS_AUTOPILOT_RUNNING){
|
||||
autopilotStateChange()
|
||||
}else {
|
||||
startAutopilotFail()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startAutopilotFail(){
|
||||
BizLoopManager.runInMainThread{
|
||||
this.viewCallback?.stopAutopilotAnimation()
|
||||
this.viewCallback?.startAutopilotFail()
|
||||
this.isPalyStartAni.set(false)
|
||||
UiThreadHandler.postDelayed({
|
||||
autopilotStateChange()
|
||||
},3000,UiThreadHandler.MODE.QUEUE)
|
||||
}
|
||||
}
|
||||
|
||||
interface AutopilotStateCallback{
|
||||
//开始动画
|
||||
fun startAutopilotAnimation()
|
||||
//结束动画
|
||||
fun stopAutopilotAnimation()
|
||||
|
||||
// 进入自动驾驶
|
||||
fun inAutopilot()
|
||||
// 自动驾驶不可用
|
||||
fun autopilotDisable()
|
||||
// 可用启动自驾
|
||||
fun canStartAutopilot()
|
||||
// 进入平行驾驶
|
||||
fun inRemoteDriver()
|
||||
|
||||
// 启动自驾成功
|
||||
fun startAutopilotSuccess()
|
||||
// 启动自驾失败
|
||||
fun startAutopilotFail()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.mogo.och.bridge.ui.drawline
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.findViewTreeViewModelStoreOwner
|
||||
import com.mogo.eagle.core.utilcode.kotlin.onClick
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.bridge.R
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
import com.mogo.och.common.module.utils.ResourcesUtils
|
||||
import kotlinx.android.synthetic.main.common_line_view.view.iv_toolkit_item_head
|
||||
import kotlinx.android.synthetic.main.common_line_view.view.iv_toolkit_item_title
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class LineView : ConstraintLayout, LineViewModel.ILineViewCallback {
|
||||
|
||||
private val TAG = "LineView"
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet)
|
||||
|
||||
constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attributeSet,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
private fun initView() {
|
||||
LayoutInflater.from(context).inflate(R.layout.common_line_view, this, true)
|
||||
iv_toolkit_item_head.setImageResource(R.drawable.common_map_line_close)
|
||||
iv_toolkit_item_title.text = ResourcesUtils.getString(R.string.common_line_info)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
|
||||
onClick {
|
||||
if (LineManager.hasDrawnGlobalTrajectory()) {
|
||||
LineManager.clearGlobalTrajectory(false)
|
||||
} else {
|
||||
val drawGlobalTrajectory = LineManager.drawGlobalTrajectory()
|
||||
if (!drawGlobalTrajectory.first) {
|
||||
ToastUtils.showLong(drawGlobalTrajectory.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val viewModel = findViewTreeViewModelStoreOwner()?.let {
|
||||
ViewModelProvider(it).get(LineViewModel::class.java)
|
||||
}
|
||||
viewModel?.setDistanceCallback(this)
|
||||
|
||||
}
|
||||
|
||||
|
||||
init {
|
||||
try {
|
||||
initView()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setImageViewResource(name: Int) {
|
||||
iv_toolkit_item_head.setImageResource(name)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.mogo.och.bridge.ui.drawline
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.bridge.autopilot.line.ILineCallback
|
||||
import com.mogo.och.bridge.autopilot.line.LineManager
|
||||
|
||||
class LineViewModel : ViewModel(), ILineCallback {
|
||||
|
||||
private val TAG = LineViewModel::class.java.simpleName
|
||||
|
||||
private var viewCallback: ILineViewCallback? = null
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
LineManager.removeListener(TAG)
|
||||
this.viewCallback = null
|
||||
}
|
||||
|
||||
fun setDistanceCallback(viewCallback: ILineViewCallback) {
|
||||
LineManager.addListener(TAG,this)
|
||||
this.viewCallback = viewCallback
|
||||
}
|
||||
|
||||
override fun clearLineSuccess() {
|
||||
this.viewCallback?.setImageViewResource(R.drawable.common_map_line_close)
|
||||
}
|
||||
|
||||
override fun drawLineSuccess() {
|
||||
this.viewCallback?.setImageViewResource(R.drawable.common_map_line_open)
|
||||
}
|
||||
|
||||
override fun drawLineFail() {
|
||||
this.viewCallback?.setImageViewResource(R.drawable.common_map_line_close)
|
||||
}
|
||||
|
||||
interface ILineViewCallback {
|
||||
fun setImageViewResource(@DrawableRes name: Int)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.mogo.och.bridge.ui.mapdirectionview;
|
||||
|
||||
/**
|
||||
* @author xiaoyuzhou
|
||||
* @date 2021/6/24 11:33 上午
|
||||
*/
|
||||
public interface IMapDirectionView {
|
||||
|
||||
/**
|
||||
* 绘制路径线
|
||||
*/
|
||||
void drawablePolyline();
|
||||
|
||||
/**
|
||||
* 清除路径线
|
||||
*/
|
||||
void clearPolyline();
|
||||
|
||||
/**
|
||||
* 设置路径中起终点marker
|
||||
*/
|
||||
void setLineMarker();
|
||||
}
|
||||
@@ -0,0 +1,404 @@
|
||||
package com.mogo.och.bridge.ui.mapdirectionview
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.findViewTreeViewModelStoreOwner
|
||||
import com.amap.api.maps.AMap
|
||||
import com.amap.api.maps.CameraUpdateFactory
|
||||
import com.amap.api.maps.TextureMapView
|
||||
import com.amap.api.maps.model.BitmapDescriptor
|
||||
import com.amap.api.maps.model.BitmapDescriptorFactory
|
||||
import com.amap.api.maps.model.CameraPosition
|
||||
import com.amap.api.maps.model.CustomMapStyleOptions
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.amap.api.maps.model.LatLngBounds
|
||||
import com.amap.api.maps.model.Marker
|
||||
import com.amap.api.maps.model.MarkerOptions
|
||||
import com.amap.api.maps.model.Polyline
|
||||
import com.amap.api.maps.model.PolylineOptions
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoChassisLocationGCJ02Listener
|
||||
import com.mogo.eagle.core.utilcode.mogo.MapAssetStyleUtils
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger.d
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler
|
||||
import com.mogo.och.common.module.R
|
||||
import com.mogo.och.bridge.autopilot.location.OchLocationManager
|
||||
import com.mogo.och.shuttle.passenger.ui.mapdirectionview.MapDirectionViewModel
|
||||
import me.jessyan.autosize.utils.AutoSizeUtils
|
||||
|
||||
/**
|
||||
* 乘客屏小地图
|
||||
*/
|
||||
class MapDirectionView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : RelativeLayout(context, attrs, defStyleAttr), IMoGoChassisLocationGCJ02Listener,
|
||||
IMapDirectionView, AMap.OnCameraChangeListener,
|
||||
MapDirectionViewModel.ItineraryViewCallback {
|
||||
companion object {
|
||||
//小地图名称
|
||||
const val TAG = "BusPassengerMapDirectionView"
|
||||
}
|
||||
|
||||
private var mapStylePath: String? = null
|
||||
private var mapStyleExtraPath: String? = null
|
||||
private var carDrawable: Int = -1
|
||||
private var compassDrawable: Int = -1
|
||||
private var startPointDrawable: Int = -1
|
||||
private var endPointDrawable: Int = -1
|
||||
private var arrivedDrawable: Int = -1
|
||||
private var unArrivedDrawable: Int = -1
|
||||
private var resetDrawableMarginRight: Int = -1
|
||||
private var resetDrawableMarginBottom: Int = -1
|
||||
private var leftPadding: Int = 100
|
||||
private var topPadding: Int = 100
|
||||
private var rightPadding: Int = 100
|
||||
private var bottomPadding: Int = 100
|
||||
|
||||
private lateinit var mAMapNaviView: TextureMapView
|
||||
private lateinit var mAMap: AMap
|
||||
private var mPolyline: Polyline? = null
|
||||
|
||||
private val mLineMarkers: MutableList<Marker> = ArrayList()
|
||||
|
||||
private lateinit var mCarMarker: Marker
|
||||
|
||||
// 除了开始站点和结束站点的中间站点 用来设置图标和地图范围圈定
|
||||
private val mLineStationLatLng: MutableList<LatLng> = ArrayList() //站点坐标数据
|
||||
var textureList: MutableList<BitmapDescriptor?> = ArrayList()
|
||||
var texIndexList: MutableList<Int> = ArrayList()
|
||||
private var mArrivedRes: BitmapDescriptor? = null
|
||||
private var mUnArrivedRes: BitmapDescriptor? = null
|
||||
|
||||
private var mStartStationPoint: BitmapDescriptor? = null
|
||||
private var mEndStationPoint: BitmapDescriptor? = null
|
||||
|
||||
private var mArrivedStationPoint: BitmapDescriptor? = null
|
||||
private var mUArrivedStationPoint: BitmapDescriptor? = null
|
||||
|
||||
|
||||
private val routeArrived: MutableList<LatLng> = ArrayList()
|
||||
private val routeArriving: MutableList<LatLng> = ArrayList()
|
||||
private var location: MogoLocation? = null
|
||||
|
||||
init {
|
||||
try {
|
||||
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.MapDirectionView)
|
||||
mapStylePath = typedArray.getString(R.styleable.MapDirectionView_mapStylePath)
|
||||
mapStyleExtraPath = typedArray.getString(R.styleable.MapDirectionView_mapStyleExtraPath)
|
||||
carDrawable = typedArray.getResourceId(R.styleable.MapDirectionView_carDrawable, -1)
|
||||
compassDrawable = typedArray.getResourceId(R.styleable.MapDirectionView_compassDrawable, -1)
|
||||
startPointDrawable =
|
||||
typedArray.getResourceId(R.styleable.MapDirectionView_startPointDrawable, -1)
|
||||
endPointDrawable =
|
||||
typedArray.getResourceId(R.styleable.MapDirectionView_endPointDrawable, -1)
|
||||
arrivedDrawable = typedArray.getResourceId(R.styleable.MapDirectionView_arrivedDrawable, -1)
|
||||
unArrivedDrawable =
|
||||
typedArray.getResourceId(R.styleable.MapDirectionView_unArrivedDrawable, -1)
|
||||
resetDrawableMarginRight = typedArray.getResourceId(
|
||||
R.styleable.MapDirectionView_resetDrawableMarginRight,
|
||||
AutoSizeUtils.dp2px(context, 40f)
|
||||
)
|
||||
resetDrawableMarginBottom = typedArray.getResourceId(
|
||||
R.styleable.MapDirectionView_resetDrawableMarginBottom,
|
||||
AutoSizeUtils.dp2px(context, 40f)
|
||||
)
|
||||
leftPadding = typedArray.getInt(R.styleable.MapDirectionView_leftPadding, 100)
|
||||
topPadding = typedArray.getInt(R.styleable.MapDirectionView_topPadding, 100)
|
||||
rightPadding = typedArray.getInt(R.styleable.MapDirectionView_rightPadding, 100)
|
||||
bottomPadding = typedArray.getInt(R.styleable.MapDirectionView_bottomPadding, 100)
|
||||
typedArray.recycle()
|
||||
initView(context)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initView(context: Context) {
|
||||
d(SceneConstant.M_BUS_P + TAG, "initView")
|
||||
val smpView = LayoutInflater.from(context).inflate(R.layout.shuttle_p_jl_map_view, this)
|
||||
mAMapNaviView = smpView.findViewById<View>(R.id.bus_p_line_amap_view) as TextureMapView
|
||||
initAMapView()
|
||||
|
||||
// 注册定位监听
|
||||
OchLocationManager.addGCJ02Listener(TAG, 1, this)
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow()
|
||||
// 注册定位监听
|
||||
OchLocationManager.removeGCJ02Listener(TAG)
|
||||
}
|
||||
|
||||
private fun initAMapView() {
|
||||
mAMap = mAMapNaviView.map
|
||||
// 设置导航地图模式,aMap是地图控制器对象。
|
||||
mAMap.mapType = AMap.MAP_TYPE_NIGHT
|
||||
|
||||
// 关闭显示实时路况图层,aMap是地图控制器对象。
|
||||
mAMap.isTrafficEnabled = false
|
||||
|
||||
// 设置 锚点 图标
|
||||
mCarMarker = mAMap.addMarker(
|
||||
MarkerOptions().icon(
|
||||
BitmapDescriptorFactory.fromResource(if (carDrawable != -1) carDrawable else R.drawable.common_map_car))
|
||||
.anchor(0.5f, 0.5f)
|
||||
)
|
||||
mArrivedRes = BitmapDescriptorFactory.fromResource(if (arrivedDrawable != -1) arrivedDrawable else R.drawable.taxi_map_arrow_arrived)
|
||||
mUnArrivedRes = BitmapDescriptorFactory.fromResource(if (unArrivedDrawable != -1) unArrivedDrawable else R.drawable.taxi_map_arrow_un_arrive)
|
||||
mStartStationPoint = BitmapDescriptorFactory.fromResource(if (startPointDrawable != -1) startPointDrawable else R.drawable.common_map_start_point)
|
||||
mEndStationPoint = BitmapDescriptorFactory.fromResource(if (endPointDrawable != -1) endPointDrawable else R.drawable.common_map_end_point)
|
||||
|
||||
mArrivedStationPoint = BitmapDescriptorFactory.fromResource(if (endPointDrawable != -1) endPointDrawable else R.drawable.common_map_arrived_point)
|
||||
mUArrivedStationPoint = BitmapDescriptorFactory.fromResource(if (endPointDrawable != -1) endPointDrawable else R.drawable.common_map_unarrived_point)
|
||||
|
||||
// 加载自定义样式
|
||||
val customMapStyleOptions = CustomMapStyleOptions().setEnable(true)
|
||||
|
||||
if (!mapStylePath.isNullOrEmpty() && !mapStyleExtraPath.isNullOrEmpty()) {
|
||||
customMapStyleOptions.styleData =
|
||||
MapAssetStyleUtils.getAssetsStyle(context, mapStylePath)
|
||||
customMapStyleOptions.styleExtraData =
|
||||
MapAssetStyleUtils.getAssetsExtraStyle(context, mapStyleExtraPath)
|
||||
}
|
||||
// 设置自定义样式
|
||||
mAMap.setCustomMapStyle(customMapStyleOptions)
|
||||
|
||||
// 设置地图的样式
|
||||
mAMap.uiSettings.apply {
|
||||
isZoomControlsEnabled = false // 地图缩放级别的交换按钮
|
||||
setAllGesturesEnabled(true) // 所有手势
|
||||
isMyLocationButtonEnabled = false // 显示默认的定位按钮
|
||||
setLogoBottomMargin(-150) //设置Logo下边界距离屏幕底部的边距,设置为负值即可
|
||||
}
|
||||
|
||||
mAMap.setOnMapLoadedListener {
|
||||
d(SceneConstant.M_BUS_P + TAG, "smp---onMapLoaded")
|
||||
// 加载自定义样式
|
||||
val options = CustomMapStyleOptions().setEnable(true)
|
||||
if (!mapStylePath.isNullOrEmpty() && !mapStyleExtraPath.isNullOrEmpty()) {
|
||||
options.styleData =
|
||||
MapAssetStyleUtils.getAssetsStyle(context, mapStylePath)
|
||||
options.styleExtraData =
|
||||
MapAssetStyleUtils.getAssetsExtraStyle(context, mapStyleExtraPath)
|
||||
}
|
||||
// 设置自定义样式
|
||||
mAMap.setCustomMapStyle(options)
|
||||
mAMap.uiSettings?.isZoomControlsEnabled = false
|
||||
|
||||
mAMapNaviView.map.setPointToCenter(
|
||||
mAMapNaviView.width / 2,
|
||||
mAMapNaviView.height / 2
|
||||
)
|
||||
}
|
||||
|
||||
//设置地图状态的监听接口
|
||||
mAMap.setOnCameraChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
val viewModel = findViewTreeViewModelStoreOwner()?.let {
|
||||
ViewModelProvider(it).get(MapDirectionViewModel::class.java)
|
||||
}
|
||||
viewModel?.setDistanceCallback(this)
|
||||
}
|
||||
|
||||
fun clearMapView() {
|
||||
UiThreadHandler.post( {
|
||||
clearPolyline()
|
||||
clearCoordinatesLatLng()
|
||||
}, UiThreadHandler.MODE.QUEUE)
|
||||
}
|
||||
|
||||
override fun onChassisLocationGCJ02(mogoLocation: MogoLocation?) {
|
||||
if (mogoLocation == null) {
|
||||
return
|
||||
}
|
||||
val currentLatLng = LatLng(mogoLocation.latitude, mogoLocation.longitude)
|
||||
|
||||
//更新车辆位置
|
||||
mCarMarker.rotateAngle = (360 - mogoLocation.heading).toFloat()
|
||||
mCarMarker.position = currentLatLng
|
||||
mCarMarker.setToTop()
|
||||
try {
|
||||
//圈定地图显示范围
|
||||
val boundsBuilder = LatLngBounds.Builder()
|
||||
routeArrived.forEach {
|
||||
boundsBuilder.include(it)
|
||||
}
|
||||
routeArriving.forEach {
|
||||
boundsBuilder.include(it)
|
||||
}
|
||||
mLineStationLatLng.forEach {
|
||||
boundsBuilder.include(it)
|
||||
}
|
||||
boundsBuilder.include(currentLatLng)
|
||||
mAMap.moveCamera(
|
||||
CameraUpdateFactory.newLatLngBoundsRect(
|
||||
boundsBuilder.build(),
|
||||
100,
|
||||
100,
|
||||
100,
|
||||
100
|
||||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun drawablePolyline() {
|
||||
if (routeArrived.isEmpty() && routeArriving.isEmpty()) {
|
||||
d(SceneConstant.M_TAXI + TAG, "没有点")
|
||||
return
|
||||
}
|
||||
try {
|
||||
texIndexList.clear()
|
||||
val allPoints = ArrayList(routeArrived)
|
||||
for (i in routeArrived.indices) {
|
||||
if (routeArrived.size > 1 && i < routeArrived.size - 1) {
|
||||
texIndexList.add(0)
|
||||
}
|
||||
}
|
||||
texIndexList.add(0)
|
||||
location?.let {
|
||||
allPoints.add(LatLng(it.latitude, it.longitude))
|
||||
}
|
||||
allPoints.addAll(routeArriving)
|
||||
for (ignored in routeArrived) {
|
||||
texIndexList.add(1)
|
||||
}
|
||||
mPolyline?.let {
|
||||
it.points = allPoints
|
||||
it.options.customTextureIndex = texIndexList
|
||||
return
|
||||
}
|
||||
if (textureList.isEmpty()) {
|
||||
textureList.add(mArrivedRes)
|
||||
textureList.add(mUnArrivedRes)
|
||||
}
|
||||
//设置线段纹理
|
||||
val polylineOptions = PolylineOptions().apply {
|
||||
addAll(allPoints)
|
||||
isUseTexture = true
|
||||
width(15f)
|
||||
lineCapType(PolylineOptions.LineCapType.LineCapRound)
|
||||
customTextureList = textureList
|
||||
customTextureIndex = texIndexList
|
||||
}
|
||||
|
||||
// 绘制线
|
||||
mPolyline = mAMap.addPolyline(polylineOptions)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearPolyline() {
|
||||
mPolyline?.remove()
|
||||
mPolyline = null
|
||||
}
|
||||
|
||||
override fun setLineMarker() {}
|
||||
|
||||
fun clearCoordinatesLatLng() {
|
||||
try {
|
||||
textureList.clear()
|
||||
texIndexList.clear()
|
||||
routeArrived.clear()
|
||||
routeArriving.clear()
|
||||
mLineStationLatLng.clear()
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
d(SceneConstant.M_BUS_P + TAG, " mCoordinatesLatLng.clear ")
|
||||
}
|
||||
|
||||
fun onCreateView(savedInstanceState: Bundle?) {
|
||||
mAMapNaviView.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
mAMapNaviView.onResume()
|
||||
}
|
||||
|
||||
fun onPause() {
|
||||
mAMapNaviView.onPause()
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
mAMapNaviView.onDestroy()
|
||||
}
|
||||
|
||||
override fun setCoordinatesLatLng(
|
||||
routeArrived: List<LatLng>,
|
||||
routeArriving: List<LatLng>,
|
||||
location: MogoLocation?
|
||||
) {
|
||||
try {
|
||||
this.routeArrived.clear()
|
||||
this.routeArrived.addAll(routeArrived)
|
||||
this.routeArriving.clear()
|
||||
this.routeArriving.addAll(routeArriving)
|
||||
this.location = location
|
||||
UiThreadHandler.post({
|
||||
drawablePolyline()
|
||||
}, UiThreadHandler.MODE.QUEUE)
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun clearLineMarkers() {
|
||||
for (i in mLineMarkers.indices) {
|
||||
mLineMarkers[i].isVisible = false
|
||||
mLineMarkers[i].remove()
|
||||
}
|
||||
mLineMarkers.clear()
|
||||
}
|
||||
|
||||
// 设置站点
|
||||
fun setLinePointMarkerAndDraw(mLineStationsList: List<LatLng>, currentIndex: Int) {
|
||||
clearLineMarkers()
|
||||
mLineStationLatLng.clear()
|
||||
mLineStationLatLng.addAll(mLineStationsList)
|
||||
if (mLineStationsList.isNotEmpty()) {
|
||||
// 起点marker, 终点marker, 过站marker, 未过站marker
|
||||
val size = mLineStationsList.size
|
||||
val mStartMarker = mAMap.addMarker(
|
||||
MarkerOptions()
|
||||
.icon(mStartStationPoint)
|
||||
)
|
||||
val mEndMarker = mAMap.addMarker(MarkerOptions().icon(mEndStationPoint))
|
||||
mStartMarker.position = mLineStationsList[0]
|
||||
mLineMarkers.add(0, mStartMarker)
|
||||
for (i in mLineStationsList.indices) {
|
||||
if (currentIndex <= i && i < size - 1 && i > 0) { //未到达
|
||||
val unArrivedMarker = mAMap.addMarker(MarkerOptions().icon(mUArrivedStationPoint))
|
||||
unArrivedMarker.position = mLineStationsList[i]
|
||||
mLineMarkers.add(i, unArrivedMarker)
|
||||
} else if (i in 1 until currentIndex) {
|
||||
val arrivedMarker = mAMap.addMarker(MarkerOptions().icon(mArrivedStationPoint))
|
||||
arrivedMarker.position = mLineStationsList[i]
|
||||
mLineMarkers.add(i, arrivedMarker)
|
||||
}
|
||||
}
|
||||
mEndMarker.position = mLineStationsList[size - 1]
|
||||
mLineMarkers.add(size - 1, mEndMarker)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCameraChange(cameraPosition: CameraPosition) {
|
||||
}
|
||||
|
||||
override fun onCameraChangeFinish(cameraPosition: CameraPosition) {}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.mogo.och.shuttle.passenger.ui.mapdirectionview
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger
|
||||
import com.mogo.och.bridge.distance.ITrajectoryListener
|
||||
import com.mogo.och.bridge.distance.TrajectoryAndDistanceManager
|
||||
|
||||
class MapDirectionViewModel: ViewModel(), ITrajectoryListener {
|
||||
|
||||
private val TAG = MapDirectionViewModel::class.java.simpleName
|
||||
|
||||
private var viewCallback: ItineraryViewCallback?=null
|
||||
|
||||
|
||||
init {
|
||||
TrajectoryAndDistanceManager.addTrajectoryListener(TAG,this)
|
||||
}
|
||||
|
||||
fun setDistanceCallback(viewCallback: ItineraryViewCallback){
|
||||
this.viewCallback = viewCallback
|
||||
}
|
||||
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
this.viewCallback = null
|
||||
TrajectoryAndDistanceManager.removeListener(TAG)
|
||||
}
|
||||
|
||||
interface ItineraryViewCallback{
|
||||
fun setCoordinatesLatLng(routeArrived: List<LatLng>, routeArriving: List<LatLng>, location: MogoLocation?)
|
||||
}
|
||||
|
||||
override fun trajectoryCallback(
|
||||
routeArrivied: MutableList<MogoLocation>,
|
||||
routeArriving: MutableList<MogoLocation>,
|
||||
location: MogoLocation
|
||||
) {
|
||||
val routeArrivedTemp: MutableList<LatLng> = ArrayList()
|
||||
val routeArrivingTemp: MutableList<LatLng> = ArrayList()
|
||||
var temp: LatLng
|
||||
for (mogoLocation in routeArrivied) {
|
||||
temp = LatLng(mogoLocation.latitude, mogoLocation.longitude)
|
||||
routeArrivedTemp.add(temp)
|
||||
}
|
||||
for (mogoLocation in routeArriving) {
|
||||
temp = LatLng(mogoLocation.latitude, mogoLocation.longitude)
|
||||
routeArrivingTemp.add(temp)
|
||||
}
|
||||
this.viewCallback?.setCoordinatesLatLng(
|
||||
routeArrivedTemp,
|
||||
routeArrivingTemp,
|
||||
location
|
||||
)
|
||||
CallerLogger.d(TAG,"已经走过的点routeArrivied:${routeArrivied.size} 未走过的点:routeArriving:${routeArriving.size}")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,870 @@
|
||||
package com.mogo.och.bridge.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import com.amap.api.maps.CoordinateConverter
|
||||
import com.amap.api.maps.model.LatLng
|
||||
import com.mogo.eagle.core.data.map.MogoLocation
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.Logger
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant
|
||||
import com.mogo.eagle.core.utilcode.util.CoordinateUtils
|
||||
import com.mogo.eagle.core.utilcode.util.DrivingDirectionUtils
|
||||
import com.mogo.och.bridge.distance.DistanceDegree
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.TreeMap
|
||||
import kotlin.math.acos
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
/**
|
||||
* @author: wangmingjun
|
||||
* @date: 2022/3/28
|
||||
*/
|
||||
object CoordinateCalculateRouteUtil {
|
||||
@JvmStatic
|
||||
fun <T> calculateRouteSumLength(points: List<T>?): Float {
|
||||
if (null == points || points.size == 0) return 0f
|
||||
var sumLength = 0f
|
||||
if (points[0] is MogoLocation) {
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as MogoLocation
|
||||
val location = points[i + 1] as MogoLocation
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
} else if (points[0] is Location) {
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as Location
|
||||
val location = points[i + 1] as Location
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
} else if (points[0] is LatLng) {
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val locationPre = points[i] as LatLng
|
||||
val location = points[i + 1] as LatLng
|
||||
val preLat = locationPre.latitude
|
||||
val preLon = locationPre.longitude
|
||||
val laLat = location.latitude
|
||||
val laLon = location.longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
}
|
||||
return sumLength
|
||||
}
|
||||
|
||||
fun calculateRouteSumLength(
|
||||
mRoutePoints: List<MogoLocation>?,
|
||||
location: MogoLocation,
|
||||
station: MogoLocation
|
||||
): Float {
|
||||
if (null == mRoutePoints || mRoutePoints.size == 0) return 0f
|
||||
var lastSumLength = 0f
|
||||
|
||||
//当前位置距离轨迹中最近的点
|
||||
val currentRouteIndex = getArrivedPointIndexNew(
|
||||
0, mRoutePoints, location.longitude, location.latitude
|
||||
)
|
||||
// 距离当前位置轨迹中最近的轨迹点坐标
|
||||
val currentPoint = mRoutePoints[currentRouteIndex]
|
||||
// 当前位置距离最近的点的距离
|
||||
val calculateCurrentdex = CoordinateUtils.calculateLineDistance(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude
|
||||
)
|
||||
|
||||
|
||||
//要前往的站在轨迹中对应的点
|
||||
val stationPointInRouteIndex = getArrivedPointIndexNew(
|
||||
currentRouteIndex, mRoutePoints,
|
||||
station.longitude,
|
||||
station.latitude
|
||||
)
|
||||
// 距离站点最近的轨迹点
|
||||
val stationPointInRoute = mRoutePoints[stationPointInRouteIndex]
|
||||
// 站点距离轨迹中最近点的距离
|
||||
val calculateLineDistance = CoordinateUtils.calculateLineDistance(
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
station.longitude, station.latitude
|
||||
)
|
||||
if (currentRouteIndex < stationPointInRouteIndex) {
|
||||
// subList 是[) 需要的是[]
|
||||
val subList = mRoutePoints.subList(currentRouteIndex, stationPointInRouteIndex + 1)
|
||||
// 轨迹点所有的距离
|
||||
lastSumLength = calculateRouteSumLength(subList)
|
||||
// region 站点坐标和 站点坐标对应轨迹点的坐标距离
|
||||
// 需要加距离 和下一个轨迹点成钝角
|
||||
if (stationPointInRouteIndex + 1 < mRoutePoints.size) {
|
||||
val lastPointsNext = mRoutePoints[stationPointInRouteIndex + 1]
|
||||
val degree = getDegree(
|
||||
station.longitude, station.latitude,
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
lastPointsNext.longitude, lastPointsNext.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength + calculateLineDistance
|
||||
}
|
||||
}
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (stationPointInRouteIndex - 1 >= 0) {
|
||||
val lastPointsPre = mRoutePoints[stationPointInRouteIndex - 1]
|
||||
val degree = getDegree(
|
||||
station.longitude, station.latitude,
|
||||
stationPointInRoute.longitude, stationPointInRoute.latitude,
|
||||
lastPointsPre.longitude, lastPointsPre.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength - calculateLineDistance
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
// region 当前位置和 对应轨迹点的坐标距离
|
||||
// 需要加距离 和下一个轨迹点成钝角
|
||||
if (currentRouteIndex + 1 < stationPointInRouteIndex) {
|
||||
val currentPointsNext = mRoutePoints[currentRouteIndex + 1]
|
||||
val degree = getDegree(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude,
|
||||
currentPointsNext.longitude, currentPointsNext.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength - calculateCurrentdex
|
||||
}
|
||||
}
|
||||
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (currentRouteIndex - 1 >= 0) {
|
||||
val lastPointsPre = mRoutePoints[currentRouteIndex - 1]
|
||||
val degree = getDegree(
|
||||
location.longitude, location.latitude,
|
||||
currentPoint.longitude, currentPoint.latitude,
|
||||
lastPointsPre.longitude, lastPointsPre.latitude
|
||||
).toDouble()
|
||||
if (degree > 90) {
|
||||
lastSumLength = lastSumLength + calculateCurrentdex
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
} else {
|
||||
val lastPoints = mRoutePoints[stationPointInRouteIndex]
|
||||
lastSumLength = CoordinateUtils.calculateLineDistance(
|
||||
lastPoints.longitude, lastPoints.latitude,
|
||||
location.longitude, location.latitude
|
||||
)
|
||||
}
|
||||
return lastSumLength
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcjListCommon(
|
||||
mContext: Context?,
|
||||
models: List<MessagePad.Location>
|
||||
): List<LatLng> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<LatLng> = ArrayList()
|
||||
for (m in models) {
|
||||
val mogoLatLng = coordinateConverterWgsToGcj(mContext, m)
|
||||
list.add(mogoLatLng)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcj(
|
||||
mContext: Context?,
|
||||
mogoLatLng: MessagePad.Location
|
||||
): LatLng {
|
||||
val mCoordinateConverter =
|
||||
CoordinateConverter(mContext)
|
||||
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS)
|
||||
mCoordinateConverter.coord(
|
||||
LatLng(
|
||||
mogoLatLng.latitude,
|
||||
mogoLatLng.longitude
|
||||
)
|
||||
)
|
||||
return mCoordinateConverter.convert()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcj(
|
||||
mContext: Context?,
|
||||
lon: Double,
|
||||
lat: Double
|
||||
): LatLng {
|
||||
val mCoordinateConverter =
|
||||
CoordinateConverter(mContext)
|
||||
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS)
|
||||
mCoordinateConverter.coord(LatLng(lat, lon))
|
||||
return mCoordinateConverter.convert()
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单粗暴 直接比较 todo 需要优化
|
||||
* @param mRoutePoints
|
||||
* @param realLon
|
||||
* @param realLat
|
||||
* @return
|
||||
*/
|
||||
fun getRemainPointListByCompare(
|
||||
mRoutePoints: List<LatLng>,
|
||||
realLon: Double,
|
||||
realLat: Double
|
||||
): List<LatLng> {
|
||||
val latePoints: MutableList<LatLng> = ArrayList()
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
if (baseLatLng != null) {
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, baseLatLng.longitude, baseLatLng.latitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in 1 until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+currentIndex+"-------是最近的点------ ");
|
||||
if (currentIndex == mRoutePoints.size - 1) {
|
||||
latePoints.add(mRoutePoints[currentIndex])
|
||||
} else if (currentIndex < mRoutePoints.size - 1) {
|
||||
latePoints.addAll(mRoutePoints.subList(currentIndex, mRoutePoints.size))
|
||||
}
|
||||
return latePoints
|
||||
}
|
||||
}
|
||||
return latePoints
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单粗暴 直接比较 todo 需要优化
|
||||
* @param mRoutePoints
|
||||
* @param realLon
|
||||
* @param realLat
|
||||
* @return 返回已经到达点的index
|
||||
*/
|
||||
fun getArrivedPointIndex(mRoutePoints: List<LatLng>, realLon: Double, realLat: Double): Int {
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
if (baseLatLng != null) {
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, baseLatLng.longitude, baseLatLng.latitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in 1 until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon, realLat, latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
}
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
fun calculateRouteSumLengthByLocation(points: List<Location>?): Float {
|
||||
if (points.isNullOrEmpty()) return 0f
|
||||
var sumLength = 0f
|
||||
|
||||
//计算全路径总距离
|
||||
var i = 0
|
||||
while (i + 1 < points.size) {
|
||||
val preLat = points[i].latitude
|
||||
val preLon = points[i].longitude
|
||||
val laLat = points[i + 1].latitude
|
||||
val laLon = points[i + 1].longitude
|
||||
val length = CoordinateUtils.calculateLineDistance(laLon, laLat, preLon, preLat)
|
||||
sumLength += length
|
||||
i++
|
||||
}
|
||||
return sumLength
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterWgsToGcjLocations(
|
||||
mContext: Context?,
|
||||
models: List<MessagePad.Location>
|
||||
): MutableList<MogoLocation> {
|
||||
//转成MogoLatLng集合
|
||||
val list = mutableListOf<MogoLocation>()
|
||||
for (m in models) {
|
||||
val mogoLatLng = coordinateConverterWgsToGcj(mContext, m)
|
||||
val location = MogoLocation()
|
||||
location.heading = m.heading.toFloat().toDouble()
|
||||
location.latitude = mogoLatLng.latitude
|
||||
location.longitude = mogoLatLng.longitude
|
||||
list.add(location)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterLatlngToLocation(models: List<LatLng>): List<MogoLocation> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<MogoLocation> = ArrayList()
|
||||
for (m in models) {
|
||||
val location = MogoLocation()
|
||||
location.latitude = m.latitude
|
||||
location.longitude = m.longitude
|
||||
list.add(location)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun coordinateConverterLocationToLatLng(
|
||||
mContext: Context?,
|
||||
models: List<MogoLocation>
|
||||
): List<LatLng> {
|
||||
//转成MogoLatLng集合
|
||||
val list: MutableList<LatLng> = ArrayList()
|
||||
for (m in models) {
|
||||
val mogoLatLng = LatLng(m.latitude, m.longitude)
|
||||
list.add(mogoLatLng)
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据前一个index,经纬度航向角,确认剩余轨迹
|
||||
* @param preIndex
|
||||
* @param mRoutePoints
|
||||
* @param realLocation
|
||||
* @return
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getRemainPointListByCompareNew(
|
||||
preIndex: Int,
|
||||
mRoutePoints: List<MogoLocation>,
|
||||
realLocation: MogoLocation
|
||||
): Map<Int, List<MogoLocation>> {
|
||||
val routePonits: MutableMap<Int, List<MogoLocation>> = HashMap()
|
||||
val latePoints: MutableList<MogoLocation> = ArrayList() // 剩余轨迹集合
|
||||
var currentIndex = 0 //记录疑似点
|
||||
if (mRoutePoints.size > 0) {
|
||||
//基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in mRoutePoints.indices) {
|
||||
val latLng = mRoutePoints[i]
|
||||
//todo 先看index对应点的方向和realLocation方向是否一致, 方向角度不能过90度
|
||||
if (realLocation.heading == realLocation.heading - latLng.heading ||
|
||||
Math.abs(realLocation.heading - latLng.heading) <= 90
|
||||
) {
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff) {
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
if (currentIndex == mRoutePoints.size - 1) {
|
||||
val location = mRoutePoints[currentIndex]
|
||||
// LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||
latePoints.add(location)
|
||||
} else {
|
||||
val locations = mRoutePoints.subList(currentIndex, mRoutePoints.size)
|
||||
for (location in locations) {
|
||||
// LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||
latePoints.add(location)
|
||||
}
|
||||
}
|
||||
routePonits[currentIndex] = latePoints
|
||||
return routePonits
|
||||
}
|
||||
return routePonits
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getArrivedPointIndexNew(
|
||||
preIndex: Int, mRoutePoints: List<MogoLocation>,
|
||||
realLocation: MogoLocation
|
||||
): Int {
|
||||
var currentIndex = 0 //记录疑似点 //基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in mRoutePoints.indices) {
|
||||
val latLng = mRoutePoints[i]
|
||||
if (realLocation.heading == realLocation.heading - latLng.heading ||
|
||||
Math.abs(realLocation.heading - latLng.heading) <= 90
|
||||
) {
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLocation.longitude,
|
||||
realLocation.latitude,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff && i > currentIndex) {
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
}
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getArrivedPointIndexNew(
|
||||
preIndex: Int, mRoutePoints: List<MogoLocation>,
|
||||
realLon: Double, realLat: Double
|
||||
): Int {
|
||||
var currentIndex = preIndex //记录疑似点 //基础点
|
||||
val baseLatLng = mRoutePoints[0]
|
||||
var baseDiffDis = CoordinateUtils.calculateLineDistance(
|
||||
realLon,
|
||||
realLat, baseLatLng.longitude, baseLatLng.longitude
|
||||
) // lon,lat, prelon, prelat
|
||||
for (i in preIndex until mRoutePoints.size) {
|
||||
val latLng = mRoutePoints[i]
|
||||
// if (realLocation.getBearing() == realLocation.getBearing() - latLng.getBearing() ||
|
||||
// Math.abs(realLocation.getBearing() - latLng.getBearing()) <= 90){
|
||||
val diff = CoordinateUtils.calculateLineDistance(
|
||||
realLon,
|
||||
realLat,
|
||||
latLng.longitude, latLng.latitude
|
||||
)
|
||||
if (baseDiffDis > diff && i > currentIndex) {
|
||||
// Logger.d(M_TAXI + "calculateRouteSumLength", "点:"+i+"-------先记录点----- ");
|
||||
baseDiffDis = diff
|
||||
currentIndex = i
|
||||
}
|
||||
// }
|
||||
}
|
||||
Logger.d("calculateRouteSumLength", "点:$currentIndex-------是最近的点------ ")
|
||||
return currentIndex
|
||||
}
|
||||
|
||||
/**
|
||||
* https://blog.csdn.net/Jeanne_0523/article/details/106056255
|
||||
* @param vertexPointX
|
||||
* @param vertexPointY
|
||||
* @param point0X 角
|
||||
* @param point0Y 角
|
||||
* @param point1X
|
||||
* @param point1Y
|
||||
* @return
|
||||
*/
|
||||
fun getDegree(
|
||||
vertexPointX: Double,
|
||||
vertexPointY: Double,
|
||||
point0X: Double,
|
||||
point0Y: Double,
|
||||
point1X: Double,
|
||||
point1Y: Double
|
||||
): Int {
|
||||
//向量的点乘
|
||||
val vector =
|
||||
(point0X - vertexPointX) * (point1X - vertexPointX) + (point0Y - vertexPointY) * (point1Y - vertexPointY)
|
||||
//向量的模乘
|
||||
val sqrt = Math.sqrt(
|
||||
(Math.abs((point0X - vertexPointX) * (point0X - vertexPointX)) + Math.abs((point0Y - vertexPointY) * (point0Y - vertexPointY)))
|
||||
* (Math.abs((point1X - vertexPointX) * (point1X - vertexPointX)) + Math.abs((point1Y - vertexPointY) * (point1Y - vertexPointY)))
|
||||
)
|
||||
//反余弦计算弧度
|
||||
val radian = Math.acos(vector / sqrt)
|
||||
//弧度转角度制
|
||||
return (180 * radian / Math.PI).toInt()
|
||||
}
|
||||
|
||||
private fun ball2xyz(thera: Double, fie: Double, r: Double): Triple<Double, Double, Double> {
|
||||
val x = r * cos(thera) * cos(fie)
|
||||
val y = r * cos(thera) * sin(fie)
|
||||
val z = r * sin(thera)
|
||||
return Triple(x, y, z)
|
||||
}
|
||||
|
||||
/**
|
||||
* https://blog.csdn.net/reborn_lee/article/details/82497577
|
||||
* 将地理经纬度转换成笛卡尔坐标系
|
||||
*/
|
||||
private fun geo2xyz(lat: Double, lng: Double): Triple<Double, Double, Double> {
|
||||
val thera = Math.PI * lat / 180
|
||||
val fie = Math.PI * lng / 180
|
||||
return ball2xyz(thera, fie, 6400.0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3个地理坐标点之间的夹角
|
||||
* @param l1 顶点坐标
|
||||
* @param l2
|
||||
* @param l3
|
||||
* @return l1为顶点的角度 精度没有angleOflocation高
|
||||
*/
|
||||
fun getDegree(l2: MogoLocation, l1: MogoLocation, l3: MogoLocation): Double {
|
||||
val (x1, y1, z1) = geo2xyz(l1.latitude, l1.longitude)
|
||||
val (x2, y2, z2) = geo2xyz(l2.latitude, l2.longitude)
|
||||
val (x3, y3, z3) = geo2xyz(l3.latitude, l3.longitude)
|
||||
|
||||
// 计算向量 P2P1 和 P2P3 的夹角 https://www.zybang.com/question/3379a30c0dd3041b3ef966803f0bf758.html
|
||||
val p1P2 = sqrt((x2 - x1).pow(2.0) + (y2 - y1).pow(2.0) + (z2 - z1).pow(2.0))
|
||||
val p2p3 = sqrt((x3 - x2).pow(2.0) + (y3 - y2).pow(2.0) + (z3 - z2).pow(2.0))
|
||||
val p = (x1 - x2) * (x3 - x2) + (y1 - y2) * (y3 - y2) + (z1 - z2) * (z3 - z2) //P2P1*P2P3
|
||||
return acos(p / (p1P2 * p2p3)) / Math.PI * 180
|
||||
}
|
||||
|
||||
fun getHeadingAngle(location: MogoLocation, nextPoint: MogoLocation): Double {
|
||||
return getHeadingAngle(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
nextPoint.longitude,
|
||||
nextPoint.latitude
|
||||
)
|
||||
}
|
||||
|
||||
fun getHeadingAngle(location: LatLng, nextPoint: LatLng): Double {
|
||||
return getHeadingAngle(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
nextPoint.longitude,
|
||||
nextPoint.latitude
|
||||
)
|
||||
}
|
||||
fun getHeadingAngle(locationLongitude: Double, locationLatitude: Double,
|
||||
nextPointLongitude: Double, nextPointLatitude: Double): Double {
|
||||
val y = sin(nextPointLongitude - locationLongitude) * cos(nextPointLatitude)
|
||||
val x = cos(locationLatitude) * sin(nextPointLatitude) - sin(locationLatitude) *
|
||||
cos(nextPointLatitude) * cos(nextPointLongitude - locationLongitude)
|
||||
var bearing = atan2(y, x)
|
||||
bearing = Math.toDegrees(bearing)
|
||||
if (bearing < 0) {
|
||||
bearing += 360.0
|
||||
}
|
||||
return 360-bearing
|
||||
}
|
||||
|
||||
fun getHeadingAngleTemp(locationLongitude: Double, locationLatitude: Double,
|
||||
nextPointLongitude: Double, nextPointLatitude: Double): Double {
|
||||
val lat1Rad = Math.toRadians(locationLatitude)
|
||||
val lat2Rad = Math.toRadians(nextPointLatitude)
|
||||
val lon1Rad = Math.toRadians(locationLongitude)
|
||||
val lon2Rad = Math.toRadians(nextPointLongitude)
|
||||
|
||||
val y = sin(lon2Rad - lon1Rad) * cos(lat2Rad)
|
||||
val x = cos(lat1Rad) * sin(lat2Rad) - sin(lat1Rad) * cos(lat2Rad) * cos(lon2Rad - lon1Rad)
|
||||
|
||||
val bearing = Math.toDegrees(atan2(y, x))
|
||||
return (bearing + 360) % 360
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 支持带航行角的和不带航向角的
|
||||
* 带航向角的会删除 航向角差大于90°的点
|
||||
* @param preIndex 上次计算缓存
|
||||
* @param mRoutePoints 轨迹点
|
||||
* @param location 目标坐标
|
||||
* @param type 1 开始站点 2 定位点 3 结束站点
|
||||
* @return Triple<Int,Boolean?,Float>
|
||||
* 距离目标坐标最近的轨迹点下标、
|
||||
* 最近点坐标是目标坐标的上一个点还是下一个点
|
||||
* 目标到最近轨迹点的距离
|
||||
*/
|
||||
@JvmStatic
|
||||
fun getNearestPointInfo(
|
||||
preIndex: Int,
|
||||
endIndex: Int,
|
||||
mRoutePoints: List<MogoLocation>,
|
||||
location: MogoLocation,
|
||||
type:Int,
|
||||
size:Int = 4,
|
||||
useHeading:Boolean = true,
|
||||
): Triple<Int,Boolean?,Float> {
|
||||
val startTime = System.currentTimeMillis()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"参数:[$preIndex $endIndex) mRoutePoints:${mRoutePoints.size} type:$type size:$size" +
|
||||
" location:(${location.latitude},${location.longitude},${location.heading})")
|
||||
var currentIndex:Int = preIndex //记录疑似点 //基础点
|
||||
// 轨迹中的点和定位点的距离集合
|
||||
val distanceMap: TreeMap<DistanceDegree, Int> = TreeMap()
|
||||
for (index in preIndex until endIndex) {
|
||||
val latLngIndex = mRoutePoints[index]
|
||||
val distance = CoordinateUtils.calculateLineDistance(
|
||||
location.longitude,
|
||||
location.latitude,
|
||||
latLngIndex.longitude,
|
||||
latLngIndex.latitude
|
||||
)
|
||||
distanceMap[DistanceDegree.obtain(distance, null,null)] = index
|
||||
if (distanceMap.size > size) {
|
||||
distanceMap.pollLastEntry()?.key?.recycle()
|
||||
}
|
||||
}
|
||||
distanceMap.forEach {
|
||||
val distanceDegree = it.key
|
||||
val pointIndex = it.value
|
||||
val currentPoint = mRoutePoints[pointIndex]// 疑似最近的点
|
||||
var nextDegree = 0.0
|
||||
var preDegree = 0.0
|
||||
|
||||
if (pointIndex + 1 < mRoutePoints.size) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
nextDegree = getDegree(location, currentPoint, nextPoint)
|
||||
}else{
|
||||
nextDegree = 135.0
|
||||
}
|
||||
// 需要减距离 和上一个轨迹点成钝角
|
||||
if (pointIndex - 1 >= 0) {
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
preDegree = getDegree(
|
||||
location,
|
||||
currentPoint,
|
||||
prePoint
|
||||
)
|
||||
}else{// 第一个个点处理
|
||||
preDegree = 135.0
|
||||
}
|
||||
fun getDegreeNext(){
|
||||
if (pointIndex + 1 < mRoutePoints.size) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val headingAngle = getHeadingAngle(currentPoint, nextPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = false
|
||||
}else{
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val headingAngle = getHeadingAngle(prePoint,currentPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = true
|
||||
}
|
||||
}
|
||||
fun getDegreePre(){
|
||||
if (pointIndex - 1 >= 0) {
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val headingAngle = getHeadingAngle(prePoint, currentPoint)
|
||||
distanceDegree.degree = headingAngle;
|
||||
distanceDegree.isNext = true
|
||||
}else{
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val headingAngle = getHeadingAngle(currentPoint,nextPoint)
|
||||
distanceDegree.degree = headingAngle
|
||||
distanceDegree.isNext = false
|
||||
}
|
||||
}
|
||||
if(nextDegree>90){
|
||||
getDegreeNext()
|
||||
}
|
||||
if(preDegree>90){
|
||||
getDegreePre()
|
||||
}
|
||||
if(preDegree<90&&nextDegree<90&&preDegree+nextDegree>90){
|
||||
if (pointIndex + 1 < mRoutePoints.size&&pointIndex - 1 >= 0) {
|
||||
val nextPoint = mRoutePoints[pointIndex + 1]
|
||||
val prePoint = mRoutePoints[pointIndex - 1]
|
||||
val degree = getDegree(currentPoint, prePoint, nextPoint)
|
||||
if(degree>90) {
|
||||
getDegreePre()
|
||||
// isNext 值无所谓了 就 ture和false都行
|
||||
// 通过航向角过滤一遍
|
||||
if(distanceDegree.degree!=null&&DrivingDirectionUtils.getAngleDiff(location.heading, distanceDegree.degree!!)<90){
|
||||
currentIndex = pointIndex
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
return Triple(currentIndex,distanceDegree.isNext,distanceDegree.distance)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据角度来排除一些点
|
||||
val iterator = distanceMap.iterator()
|
||||
// 有航向角比较航向角
|
||||
while (iterator.hasNext()) {
|
||||
val next = iterator.next()
|
||||
val key = next.key
|
||||
if (key.degree == null) {
|
||||
key.recycle()
|
||||
iterator.remove()
|
||||
} else {
|
||||
if (location.heading != 0.0 && useHeading) {
|
||||
key.degree?.let {
|
||||
val dexAngle = DrivingDirectionUtils.getAngleDiff(location.heading, it)
|
||||
if (dexAngle > 90) {
|
||||
key.recycle()
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(distanceMap.size==0&&size<16){
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return getNearestPointInfo(preIndex,endIndex,mRoutePoints,location,type,size+2)
|
||||
}
|
||||
|
||||
// 最近点中包含上次计算的点和上次计算的最近的一个点
|
||||
if(distanceMap.containsValue(preIndex)&&distanceMap.containsValue(preIndex+1)&&type==1){
|
||||
var preIndexDistance: com.mogo.och.bridge.distance.DistanceDegree?=null
|
||||
var preIndexNextDistance: com.mogo.och.bridge.distance.DistanceDegree?=null
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val key = en.key
|
||||
val value = en.value
|
||||
if(value==preIndex){
|
||||
preIndexDistance = key
|
||||
}else if(value==preIndex+1){
|
||||
preIndexNextDistance = key
|
||||
}
|
||||
}
|
||||
if(preIndexDistance!=null&&preIndexNextDistance!=null){
|
||||
if(preIndexDistance!!.distance<preIndexNextDistance!!.distance){
|
||||
currentIndex = preIndex
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,preIndexDistance?.isNext,preIndexDistance!!.distance)
|
||||
}else{
|
||||
currentIndex = preIndex+1
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,preIndexNextDistance?.isNext,preIndexNextDistance!!.distance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var maxIndex = 0
|
||||
var minIndex = Int.MAX_VALUE
|
||||
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val value = en.value
|
||||
if(value<minIndex){
|
||||
minIndex = value
|
||||
}
|
||||
if(value>maxIndex){
|
||||
maxIndex = value
|
||||
}
|
||||
}
|
||||
|
||||
val middleVale =minIndex + (maxIndex-minIndex)/2
|
||||
when (type) {
|
||||
1 -> {// 求开始站点
|
||||
val iteratorRemove = distanceMap.iterator()
|
||||
while (iteratorRemove.hasNext()) {
|
||||
val next = iteratorRemove.next()
|
||||
val key = next.key
|
||||
if(next.value>middleVale){
|
||||
key.recycle()
|
||||
iteratorRemove.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
3 -> {// 求结束站点
|
||||
val iteratorRemove = distanceMap.iterator()
|
||||
while (iteratorRemove.hasNext()) {
|
||||
val next = iteratorRemove.next()
|
||||
val key = next.key
|
||||
if(next.value<middleVale){
|
||||
key.recycle()
|
||||
iteratorRemove.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
// 根据距离来计算 最近的点 只有一个前面的点
|
||||
var tempDistance = Float.MAX_VALUE
|
||||
var isNext:Boolean? = null
|
||||
distanceMap.iterator().forEach { en ->
|
||||
val key = en.key
|
||||
val value = en.value
|
||||
// 排除没有第一个值0是
|
||||
if(value==preIndex+1&&preIndex!=0&&type==1){
|
||||
currentIndex = value
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,key.isNext,key.distance)
|
||||
}
|
||||
key.distance.let {
|
||||
if (it < tempDistance) {
|
||||
tempDistance = it
|
||||
currentIndex = value
|
||||
isNext = key.isNext
|
||||
}
|
||||
}
|
||||
}
|
||||
val iterator1 = distanceMap.iterator()
|
||||
while (iterator1.hasNext()) {
|
||||
iterator1.next().key.recycle()
|
||||
iterator1.remove()
|
||||
}
|
||||
distanceMap.clear()
|
||||
Logger.d(SceneConstant.M_OCHCOMMON + "calculateRouteSumLength",
|
||||
"计算时间:${System.currentTimeMillis()-startTime}")
|
||||
return Triple(currentIndex,isNext,tempDistance)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/dp_282"
|
||||
android:layout_height="@dimen/dp_282"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/aciv_autopilot_bg"
|
||||
android:src="@drawable/common_autopilot_bg"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_width="@dimen/dp_282"
|
||||
android:layout_height="@dimen/dp_282" />
|
||||
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/aciv_autopilot_state"
|
||||
android:src="@drawable/common_autopilot_enable"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/gl_horizontal_top"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/gl_horizontal_bottom"
|
||||
android:layout_width="@dimen/dp_180"
|
||||
android:layout_height="@dimen/dp_180" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/gl_horizontal_top"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="@dimen/dp_37"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/gl_horizontal_bottom"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintGuide_begin="@dimen/dp_245"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_autopilot_head"
|
||||
android:textColor="@color/common_B3FFFFFF"
|
||||
android:textSize="@dimen/dp_32"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gl_horizontal_top"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@+id/actv_autopilot_state"
|
||||
android:text="AD"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_autopilot_state"
|
||||
android:textColor="@color/common_B3FFFFFF"
|
||||
android:textSize="@dimen/dp_32"
|
||||
app:layout_constraintTop_toBottomOf="@+id/actv_autopilot_head"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/gl_horizontal_bottom"
|
||||
android:text="START"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_pxjs_state"
|
||||
android:textColor="@color/common_19FFCB"
|
||||
android:visibility="gone"
|
||||
android:textSize="@dimen/dp_32"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gl_horizontal_top"
|
||||
app:layout_constraintBottom_toTopOf="@+id/gl_horizontal_bottom"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:text="平行驾驶"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/aciv_autopilot_running_ani"
|
||||
android:src="@drawable/start_auto_001"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="@dimen/dp_280"
|
||||
android:layout_height="@dimen/dp_280" />
|
||||
</merge>
|
||||
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/dp_939"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/common_error_vin">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_error_head"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_60"
|
||||
android:layout_marginStart="@dimen/dp_60"
|
||||
android:layout_marginEnd="@dimen/dp_60"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/dp_46"
|
||||
app:layout_constraintBottom_toTopOf="@+id/actv_error_body"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:text="VIN码不匹配!!!" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_error_body"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginStart="@dimen/dp_60"
|
||||
android:layout_marginEnd="@dimen/dp_60"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_41"
|
||||
android:layout_marginBottom="@dimen/dp_39"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/dp_40"
|
||||
app:layout_constraintBottom_toTopOf="@+id/actv_error_body_red"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/actv_error_head"
|
||||
android:text="请暂停运营并上报问题,待问题解决后用车" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_error_body_red"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginStart="@dimen/dp_60"
|
||||
android:layout_marginEnd="@dimen/dp_60"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/holo_red_dark"
|
||||
android:textSize="@dimen/dp_40"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/actv_error_body"
|
||||
android:text="【仍继续用车有安全风险!!!】" />
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/actv_see"
|
||||
android:layout_width="@dimen/dp_350"
|
||||
android:layout_height="@dimen/dp_130"
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_marginBottom="@dimen/dp_80"
|
||||
android:background="@drawable/common_error_vin_submit"
|
||||
android:gravity="center"
|
||||
android:text="我知道了"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/dp_46"
|
||||
app:layout_constraintTop_toBottomOf="@+id/actv_error_body_red"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
36
OCH/common/bridge/src/main/res/layout/common_line_view.xml
Normal file
36
OCH/common/bridge/src/main/res/layout/common_line_view.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@color/acc_default_txt_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_toolkit_item_head"
|
||||
android:layout_width="@dimen/dp_160"
|
||||
android:layout_height="@dimen/dp_160"
|
||||
android:scaleType="fitXY"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/common_map_line_close"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/iv_toolkit_item_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_1"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:text="车道指引"
|
||||
android:textColor="@color/color_FFFFFF"
|
||||
android:textSize="@dimen/sp_38"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/iv_toolkit_item_head"/>
|
||||
|
||||
</merge>
|
||||
Reference in New Issue
Block a user