优化了道路事件的触发算法,主要分为以下步骤:

触发道路事件的条件:
0、道路事件必须有朝向,角度>=0;
1、距离《500
2、道路事件方向与当前行驶方向角度偏《20度以内
3、当前车辆行驶方向与事件位置之间夹角《20度
This commit is contained in:
董宏宇
2020-11-25 16:39:34 +08:00
parent b085e49cc9
commit 33aedd3aef
7 changed files with 156 additions and 119 deletions

View File

@@ -76,78 +76,94 @@ public class V2XAlarmServer {
// 检测道路事件是否需UGC问答
V2XEarlyWarningServer.roadEventUgcCheck(currentLocation);
}
// Logger.w(MODULE_NAME, "V2X预警--车辆状态:" + currentLocation);
// Logger.w(MODULE_NAME, "V2X预警--车辆速度:" + currentLocation.getSpeed());
// Logger.w(MODULE_NAME, "V2X预警--v2XRoadEventEntityList" + GsonUtil.jsonFromObject(v2XRoadEventEntityList));
// 60(km/h)
if (currentLocation != null && v2XRoadEventEntityList != null) {
// 因为集合是按照距离排序后的所以这里检索出来第一个就发出警告
for (V2XRoadEventEntity v2XRoadEventEntity : v2XRoadEventEntityList) {
// 先计算当前车辆的车头朝向是否与事件方向相同这里采用的是区间值只要在20度上下即可使用
// 道路事件必须有朝向,角度>=0;
//Logger.w(MODULE_NAME,
// "V2X预警--车辆与事件信息:" +
// "\n事件名称" + markerNoveltyInfo.getNoveltyInfo().getContentData().getTitle() +
// "\n事件角度" + markerNoveltyInfo.getLocation().getAngle() +
// "\n车头角度" + currentLocation.getAngle() +
// "\n角度差值" + Math.abs(currentLocation.getAngle() - markerNoveltyInfo.getLocation().getAngle()));
// 0、道路事件必须有朝向角度>=0;
if (v2XRoadEventEntity.getLocation().getAngle() >= 0) {
// 计算车辆距离指定气泡的距离
MarkerLocation eventLocation = v2XRoadEventEntity.getLocation();
// 判断是否到达了触发距离,20 ~ 500,
// 1、判断是否到达了触发距离,20 ~ 500,
if (v2XRoadEventEntity.getDistance() <= 500) {
double eventAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
currentLocation.getLongitude(),
currentLocation.getLatitude(),
eventLocation.getLon(),
eventLocation.getLat(),
(int) currentLocation.getBearing()
);
if (0 <= eventAngle && eventAngle <= 20) {
// 判断是否已经提示过道路事件
boolean isAlreadyAlert = false;
String lastTime = mAlertRoadEventList.get(v2XRoadEventEntity);
if (!TextUtils.isEmpty(lastTime)) {
long timeSpan = TimeUtils.getTimeSpanByNow(lastTime, TimeConstants.MIN);
// 2、道路事件方向与当前行驶方向角度偏差《20度以内
double carBearing = currentLocation.getBearing();
double eventBearing = eventLocation.getAngle();
double diffAngle = DrivingDirectionUtils.getAngleDiff(carBearing, eventBearing);
if (diffAngle < 20) {
// 3、计算当前车辆行驶方向与事件位置之间夹角《20度保证道路事件在车辆前方
double eventAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
currentLocation.getLongitude(),
currentLocation.getLatitude(),
eventLocation.getLon(),
eventLocation.getLat(),
(int) currentLocation.getBearing()
);
if (0 <= eventAngle && eventAngle <= 20) {
// 判断是否已经提示过道路事件
boolean isAlreadyAlert = false;
String lastTime = mAlertRoadEventList.get(v2XRoadEventEntity);
if (!TextUtils.isEmpty(lastTime)) {
long timeSpan = TimeUtils.getTimeSpanByNow(lastTime, TimeConstants.MIN);
// Logger.w(MODULE_NAME,
// "V2X预警--事件ID" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
// "\n上一次预警时间" + lastTime +
// "\n距离当前时间" + timeSpan);
// 5分钟内不重复提醒
if (timeSpan < 5) {
isAlreadyAlert = true;
// 5分钟内不重复提醒
if (timeSpan < 5) {
isAlreadyAlert = true;
}
}
// 进行提醒
if (!isAlreadyAlert) {
Logger.w(MODULE_NAME, "V2X预警--车辆与事件信息:" +
"\n事件详情ID" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
"\n事件详情" + GsonUtil.jsonFromObject(v2XRoadEventEntity.getNoveltyInfo()) +
"\n距离" + v2XRoadEventEntity.getDistance() + "" +
"\n是否已经提醒" + isAlreadyAlert +
"\n当前车辆-经度:" + currentLocation.getLongitude() +
"\n当前车辆-经度:" + currentLocation.getLatitude() +
"\n当前车辆-角度:" + currentLocation.getBearing() +
"\n道路事件-经度:" + eventLocation.getLon() +
"\n道路事件-经度:" + eventLocation.getLat() +
"\n道路事件-角度:" + eventLocation.getAngle() +
"\n夹角角度" + eventAngle + ""
);
mAlertRoadEventList.put(v2XRoadEventEntity, TimeUtils.getNowString());
return v2XRoadEventEntity;
}
return null;
} else {
// Logger.w(MODULE_NAME, "V2X预警--事件与车头角度夹角过大:" +
// "\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
// "\n当前车辆-经度:" + currentLocation.getLongitude() +
// "\n当前车辆-经度:" + currentLocation.getLatitude() +
// "\n当前车辆-角度:" + currentLocation.getBearing() +
// "\n道路事件-经度:" + eventLocation.getLon() +
// "\n道路事件-经度:" + eventLocation.getLat() +
// "\n道路事件-角度:" + eventLocation.getAngle() +
// "\n夹角角度" + eventAngle + " 度"
// );
}
Logger.w(MODULE_NAME, "V2X预警--车辆与事件信息:" +
"\n距离" + v2XRoadEventEntity.getDistance() + "" +
"\n是否已经提醒" + isAlreadyAlert +
"\n事件ID" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
"\n事件详情" + GsonUtil.jsonFromObject(v2XRoadEventEntity.getNoveltyInfo())
);
// 进行提醒
if (!isAlreadyAlert) {
mAlertRoadEventList.put(v2XRoadEventEntity, TimeUtils.getNowString());
return v2XRoadEventEntity;
}
return null;
} else {
Logger.w(MODULE_NAME, "V2X预警--事件与车头角度夹角过大:" +
"\n角度" + eventAngle + "" +
"\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId()
Logger.w(MODULE_NAME,
"V2X预警--车头方向与事件方向角度不一致:" +
"\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
"\n车头方向 " + carBearing +
"\n事件方向" + eventBearing +
"\n角度差值" + diffAngle
);
}
} else {
Logger.w(MODULE_NAME, "V2X预警--车辆距离事件距离大于500米了" +
"\n距离" + v2XRoadEventEntity.getDistance() + "" +
"\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId()
);
// Logger.w(MODULE_NAME, "V2X预警--车辆距离事件距离大于500米了" +
// "\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
// "\n距离" + v2XRoadEventEntity.getDistance() + "米"
// );
}
} else {
Logger.w(MODULE_NAME,
"V2X预警--车头方向与事件方向角度不一致:" +
"\n车头方向: " + currentLocation.getBearing() +
"\n事件方向" + v2XRoadEventEntity.getLocation().getAngle()
Logger.e(MODULE_NAME,
"V2X预警--道路事件没有角度信息" +
"\n事件详情:" + v2XRoadEventEntity.getNoveltyInfo().getInfoId()
);
}
}
@@ -189,11 +205,11 @@ public class V2XAlarmServer {
switch (levelListBean.getLevel()) {
//正常
case "NORMAL":
Logger.d(MODULE_NAME, "驾驶疲劳程度: 正常");
//Logger.d(MODULE_NAME, "驾驶疲劳程度: 正常");
break;
//轻度
case "SLIGHT":
Logger.w(MODULE_NAME, "驾驶疲劳程度: 轻度");
//Logger.w(MODULE_NAME, "驾驶疲劳程度: 轻度");
if (!mV2XFatigueDrivingEventLevel.contains("SLIGHT")) {
mV2XFatigueDrivingEventLevel.add("SLIGHT");
drivingShowEntity.setShowWindow(false);
@@ -208,15 +224,15 @@ public class V2XAlarmServer {
break;
//中度
case "MODERATE":
Logger.e(MODULE_NAME, "驾驶疲劳程度: 中度");
//Logger.e(MODULE_NAME, "驾驶疲劳程度: 中度");
warningParkPoi(location, onFatigueDrivingListener, drivingShowEntity, levelListBean);
break;
//重度
case "SEVERE":
Logger.e(MODULE_NAME, "驾驶疲劳程度: 重度");
//Logger.e(MODULE_NAME, "驾驶疲劳程度: 重度");
break;
default:
Logger.e(MODULE_NAME, "驾驶疲劳程度: 超出定义范围");
//Logger.e(MODULE_NAME, "驾驶疲劳程度: 超出定义范围");
break;
}
}
@@ -238,7 +254,7 @@ public class V2XAlarmServer {
LocationUtils.geoCodeSearch(location, new IMogoGeoSearchListener() {
@Override
public void onRegeocodeSearched(MogoRegeocodeResult regeocodeResult) {
Logger.i(MODULE_NAME, "根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
//Logger.i(MODULE_NAME, "根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
String keyword = "停车场";
boolean isHighWay = false;
// 如果当前位置是高速则推荐服务区

View File

@@ -4,22 +4,18 @@ import android.content.Intent;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.mogo.map.MogoLatLng;
import com.mogo.map.location.MogoLocation;
import com.mogo.module.common.entity.MarkerLocation;
import com.mogo.module.common.entity.V2XMessageEntity;
import com.mogo.module.common.entity.V2XRoadEventEntity;
import com.mogo.module.v2x.V2XConst;
import com.mogo.module.v2x.V2XServiceManager;
import com.mogo.module.v2x.utils.DrivingDirectionUtils;
import com.mogo.module.v2x.utils.EventTypeUtils;
import com.mogo.module.v2x.utils.V2XUtils;
import com.mogo.service.share.IMogoTanluProvider;
import com.mogo.service.share.TanluUploadParams;
import com.mogo.utils.logger.Logger;
import com.mogo.utils.network.utils.GsonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
@@ -30,7 +26,7 @@ import static com.mogo.module.v2x.V2XConst.MODULE_NAME;
public class V2XEarlyWarningServer {
private static final String TAG = "V2XEarlyWarningServer";
private static List<String> alertMessageId = new ArrayList<>();
private static ArrayList<String> alertMessageId = new ArrayList<>();
/**
* 对提醒过的道路事件进行UGC检测
@@ -54,37 +50,50 @@ public class V2XEarlyWarningServer {
(int) currentLocation.getBearing()
);
// 判断车辆行驶角度是否与事件相反,相反的话表示已经行驶过去了
if (90 <= eventAngle && !alertMessageId.contains(v2XRoadEventEntity.getNoveltyInfo().getInfoId())) {
// 封路、施工、拥堵、拥堵 才会有UGC提示
if (EventTypeUtils.isNeedRoadEventUgc(v2XRoadEventEntity.getPoiType())) {
double carBearing = currentLocation.getBearing();
String roadInfoId = v2XRoadEventEntity.getNoveltyInfo().getInfoId();
Logger.w(MODULE_NAME + "_" + TAG, "V2X预警UGC--事件与车头角度夹角过大:" +
"\n角度" + eventAngle + "" +
"\n事件详情" + v2XRoadEventEntity.getNoveltyInfo().getInfoId() +
"\n库存事件:" + V2XAlarmServer.mAlertRoadEventList.size()
);
Logger.w(MODULE_NAME,
"V2X预警--UGC检测" +
"\n事件详情" + roadInfoId +
"\n车头方向: " + carBearing +
"\n车与事件夹角" + eventAngle +
"\n已经UGC的事件" + GsonUtil.jsonFromObject(alertMessageId)
);
// 记录已经 UGC 提醒过的数据
alertMessageId.add(v2XRoadEventEntity.getNoveltyInfo().getInfoId());
// 判断是否预警过了
if (!alertMessageId.contains(roadInfoId)) {
// 判断车辆行驶角度是否与事件相反,相反的话表示已经行驶过去了
if (80 <= eventAngle) {
// 封路、施工、拥堵、拥堵 才会有UGC提示
if (EventTypeUtils.isNeedRoadEventUgc(v2XRoadEventEntity.getPoiType())) {
Logger.w(MODULE_NAME + "_" + TAG, "V2X预警UGC--事件与车头角度夹角过大:" +
"\n角度" + eventAngle + "" +
"\n事件详情" + roadInfoId +
"\n库存事件" + V2XAlarmServer.mAlertRoadEventList.size()
);
// 加载数据
V2XMessageEntity<V2XRoadEventEntity> v2xMessageEntity = new V2XMessageEntity<>();
// 控制类型
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_EVENT_UGC_WARNING);
// 设置数据
v2xMessageEntity.setContent(v2XRoadEventEntity);
// 控制展示状态
v2xMessageEntity.setShowState(true);
// 弹出UGC
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2xMessageEntity);
LocalBroadcastManager.getInstance(V2XUtils.getApp()).sendBroadcast(intent);
// 记录已经 UGC 提醒过的数据
alertMessageId.add(roadInfoId);
// 加载数据源
V2XMessageEntity<V2XRoadEventEntity> v2xMessageEntity = new V2XMessageEntity<>();
// 控制类型
v2xMessageEntity.setType(V2XMessageEntity.V2XTypeEnum.ALERT_EVENT_UGC_WARNING);
// 设置数据
v2xMessageEntity.setContent(v2XRoadEventEntity);
// 控制展示状态
v2xMessageEntity.setShowState(true);
// 弹出UGC
Intent intent = new Intent(V2XConst.BROADCAST_SCENE_HANDLER_ACTION);
intent.putExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY, v2xMessageEntity);
LocalBroadcastManager.getInstance(V2XUtils.getApp()).sendBroadcast(intent);
}
// 移出已经预警的事件列表
//V2XAlarmServer.mAlertRoadEventList.remove(v2XRoadEventEntity);
}
// 移出已经预警的事件列表
//V2XAlarmServer.mAlertRoadEventList.remove(v2XRoadEventEntity);
}
}
}

View File

@@ -154,11 +154,11 @@ public class V2XLocationListener implements IMogoLocationListener, CarStatusList
V2XServiceManager.getV2XStatusManager().getLocation());
// 距离是否大于10米 && 消息是否不为空
if (v2XRoadEventEntity != null && v2XRoadEventEntity.getDistance() >= 5) {
Logger.w(MODULE_NAME,
//"\nV2X预警--当前导航状态:" + V2XServiceManager.getNavi().isNaviing() +
//"\nV2X预警--roadEventIsNullCount:" + roadEventIsNullCount +
"\nV2X预警--当前预警事件:" + v2XRoadEventEntity
);
// Logger.w(MODULE_NAME,
// //"\nV2X预警--当前导航状态:" + V2XServiceManager.getNavi().isNaviing() +
// //"\nV2X预警--roadEventIsNullCount:" + roadEventIsNullCount +
// "\nV2X预警--当前预警事件:" + v2XRoadEventEntity
// );
// Logger.w(MODULE_NAME, "V2X预警--前方数据距离:" + v2XRoadEventEntity.getDistance());
// 触发展示操作
TrackUtils.trackV2xRoadProduceEvent(1);
@@ -229,7 +229,7 @@ public class V2XLocationListener implements IMogoLocationListener, CarStatusList
LocationUtils.geoCodeSearch(location, new IMogoGeoSearchListener() {
@Override
public void onRegeocodeSearched(MogoRegeocodeResult regeocodeResult) {
Logger.i(MODULE_NAME, " 根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
//Logger.i(MODULE_NAME, " 根据经纬度查询结果为:" + regeocodeResult.getRegeocodeAddress().getFormatAddress());
location.setAddress(regeocodeResult.getRegeocodeAddress().getFormatAddress());
// 如果有 "高速"、"环线"、"快速路"等字眼的,视为封闭式道路,流程结束;
if (regeocodeResult.getRegeocodeAddress().getFormatAddress().contains("高速")
@@ -257,7 +257,7 @@ public class V2XLocationListener implements IMogoLocationListener, CarStatusList
.queryIllegalPark(new V2XRefreshCallback<MarkerResponse>() {
@Override
public void onSuccess(MarkerResponse result) {
Logger.i(MODULE_NAME, "搜索附近的违章停车点 成功:" + GsonUtil.jsonFromObject(result));
//Logger.i(MODULE_NAME, "搜索附近的违章停车点 成功:" + GsonUtil.jsonFromObject(result));
if (result != null) {
if (result.getResult().getExploreWay().size() > 0) {
V2XMessageEntity<List<MarkerExploreWay>> entity = new V2XMessageEntity<>();

View File

@@ -60,7 +60,7 @@ public class MoGoV2XMarkerManager implements IMoGoV2XMarkerManager {
@Override
public void drawableLastAllPOI() {
Logger.w(MODULE_NAME, "V2X---绘制上一次的POI回调给Launcher底层逻辑让其进行绘制");
//Logger.w(MODULE_NAME, "V2X---绘制上一次的POI回调给Launcher底层逻辑让其进行绘制");
// 清除连接线
V2XServiceManager.getMoGoV2XPolylineManager().clearLine();
clearAlarmPOI();
@@ -521,7 +521,7 @@ public class MoGoV2XMarkerManager implements IMoGoV2XMarkerManager {
try {
V2XServiceManager.getMapUIController().changeMapMode(EnumMapUI.NorthUP_2D);
V2XServiceManager.getMoGoV2XStatusManager().setRoadEventPOIShow(TAG, true);
Logger.i(MODULE_NAME, "绘制道路事件====drawableAlarmPOI");
//Logger.i(MODULE_NAME, "绘制道路事件====drawableAlarmPOI");
// 清除原来的大而全的新鲜事儿
clearALLPOI();
if (roadEventEntity.getLocation() != null) {

View File

@@ -23,7 +23,7 @@ public class SceneBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
try {
V2XMessageEntity v2XMessageEntity = (V2XMessageEntity) intent.getSerializableExtra(V2XConst.BROADCAST_SCENE_EXTRA_KEY);
Logger.d(TAG, "v2XMessageEntity:" + GsonUtil.jsonFromObject(v2XMessageEntity));
//Logger.d(TAG, "v2XMessageEntity:" + GsonUtil.jsonFromObject(v2XMessageEntity));
V2XScenarioManager.getInstance().handlerMessage(v2XMessageEntity);
} catch (Exception e) {
e.printStackTrace();

View File

@@ -55,7 +55,7 @@ public class V2XScenarioManager implements IV2XScenarioManager {
@Override
public void handlerMessage(V2XMessageEntity v2XMessageEntity) {
Logger.d(MODULE_NAME, "处理V2X场景" + GsonUtil.jsonFromObject(v2XMessageEntity));
//Logger.d(MODULE_NAME, "处理V2X场景" + GsonUtil.jsonFromObject(v2XMessageEntity));
synchronized (V2XScenarioManager.class) {
// 展示
V2XUtils.runOnUiThread(() -> {

View File

@@ -1,5 +1,7 @@
package com.mogo.module.v2x.utils;
import static java.lang.Math.PI;
/**
* author : donghongyu
* e-mail : 1358506549@qq.com
@@ -22,8 +24,8 @@ public class DrivingDirectionUtils {
public static int getDegreeOfCar2Poi(double carLon, double carLat, double poiLon, double poiLat, int carAngle) {
int poiAngle = 0;
// 以子午线作为y轴 计算两点的余切 再将余切值转化为角度
double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / Math.PI);
double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / PI);
//Log.w(MODULE_NAME, "getDegreeOfCar2Poi_计算车辆行驶方向 与 poi点到车辆的连线 间的夹角_angle===" + _angle);
if (poiLon > carLon) {
// poi 在 车辆位置的第1象限
if (poiLat > carLat) {
@@ -46,9 +48,27 @@ public class DrivingDirectionUtils {
return calculationAngle(poiAngle, carAngle);
}
/**
* 计算两个行驶方向间的夹角 计算结果小于180度
*
* @param angle0
* @param angle1
* @return
*/
public static int calculationAngle(int angle0, int angle1) {
// 获取两方向间夹角
int angle = Math.abs(angle0 - angle1);
if (angle > 180) {
int minAngle = Math.min(angle0, angle1);
int maxAngle = Math.max(angle0, angle1);
return 180 - Math.abs(minAngle + 180 - maxAngle);
} else {
return angle;
}
}
/**
* 计算车辆行驶方向 与 poi点到车辆的连线 间的夹角
* 计算车辆行驶方向角度,起点&终点经纬度
*
* @param carLat 车辆位置 lat
* @param carLon 车辆位置 lon
@@ -58,7 +78,7 @@ public class DrivingDirectionUtils {
public static int getCarAngle(double carLat, double carLon, double poiLat, double poiLon) {
int poiAngle = 0;
// 以子午线作为y轴 计算两点的余切 再将余切值转化为角度
double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / Math.PI);
double _angle = Math.atan2(Math.abs(carLon - poiLon), Math.abs(carLat - poiLat)) * (180 / PI);
if (poiLon > carLon) {
// poi 在 车辆位置的第1象限
@@ -87,23 +107,15 @@ public class DrivingDirectionUtils {
}
/**
* 计算两个行驶方向间的夹角 计算结果小于180度
* 计算两个角度差值
*
* @param angle0
* @param angle1
* @return
* @param angle1 角度1
* @param angle2 角度2
* @return 差值
*/
public static int calculationAngle(int angle0, int angle1) {
// 获取两方向间夹角
int angle = Math.abs(angle0 - angle1);
if (angle > 180) {
int minAngle = Math.min(angle0, angle1);
int maxAngle = Math.max(angle0, angle1);
return 180 - Math.abs(minAngle + 180 - maxAngle);
} else {
return angle;
}
public static double getAngleDiff(double angle1, double angle2) {
// 两个角度差值较小
return 180 - Math.abs(Math.abs(angle1 - angle2) - 180);
}
}