文章目的
项目开发所需,所以结合百度地图提供的小车平滑轨迹移动,自己写的demo
实现效果
代码下载
下载链接
下面是实现的关键步骤
集成百度地图
怎么集成自然是看百度地图开发平台提供的文档。
文档连接
规划线路
看百度地图的文档,写一个规划线路的工具类(驾车的)
package com.wzhx.car_smooth_move_demo.utils;
import android.util.Log;
import com.baidu.mapapi.search.route.BikingRouteResult;
import com.baidu.mapapi.search.route.DrivingRoutePlanOption;
import com.baidu.mapapi.search.route.DrivingRouteResult;
import com.baidu.mapapi.search.route.IndoorRouteResult;
import com.baidu.mapapi.search.route.MassTransitRouteResult;
import com.baidu.mapapi.search.route.OnGetRoutePlanResultListener;
import com.baidu.mapapi.search.route.PlanNode;
import com.baidu.mapapi.search.route.RoutePlanSearch;
import com.baidu.mapapi.search.route.TransitRouteResult;
import com.baidu.mapapi.search.route.WalkingRouteResult;
import com.wzhx.car_smooth_move_demo.listener.OnGetDrivingResultListener;
public class RoutePlanUtil {
private RoutePlanSearch mRoutePlanSearch = RoutePlanSearch.newInstance();
private OnGetDrivingResultListener getDrivingResultListener;
private OnGetRoutePlanResultListener getRoutePlanResultListener = new OnGetRoutePlanResultListener() {
@Override
public void onGetWalkingRouteResult(WalkingRouteResult walkingRouteResult) {
}
@Override
public void onGetTransitRouteResult(TransitRouteResult transitRouteResult) {
}
@Override
public void onGetMassTransitRouteResult(MassTransitRouteResult massTransitRouteResult) {
}
@Override
public void onGetDrivingRouteResult(DrivingRouteResult drivingRouteResult) {
Log.e("测试", drivingRouteResult.error + ":" + drivingRouteResult.status);
getDrivingResultListener.onSuccess(drivingRouteResult);
}
@Override
public void onGetIndoorRouteResult(IndoorRouteResult indoorRouteResult) {
}
@Override
public void onGetBikingRouteResult(BikingRouteResult bikingRouteResult) {
}
};
public RoutePlanUtil(OnGetDrivingResultListener getDrivingResultListener) {
this.getDrivingResultListener = getDrivingResultListener;
this.mRoutePlanSearch.setOnGetRoutePlanResultListener(this.getRoutePlanResultListener);
}
public void routePlan(PlanNode startNode, PlanNode endNode){
mRoutePlanSearch.drivingSearch((new DrivingRoutePlanOption())
.from(startNode).to(endNode)
.policy(DrivingRoutePlanOption.DrivingPolicy.ECAR_TIME_FIRST)
.trafficPolicy(DrivingRoutePlanOption.DrivingTrafficPolicy.ROUTE_PATH_AND_TRAFFIC));
}
}
规划线路后需要将实时路况索引保存,为后面画图需要
// 设置路段实时路况索引
List<DrivingRouteLine.DrivingStep allStep = selectedRouteLine.getAllStep();
mTrafficTextureIndexList.clear();
for (int j = 0; j < allStep.size(); j++) {
if (allStep.get(j).getTrafficList() != null && allStep.get(j).getTrafficList().length 0) {
for (int k = 0; k < allStep.get(j).getTrafficList().length; k++) {
mTrafficTextureIndexList.add(allStep.get(j).getTrafficList()[k]);
}
}
}
要将路线规划的路线上的路段再细分(切割),这样小车移动才会平滑
/**
* 将规划好的路线点进行截取
* 参考百度给的小车平滑轨迹移动demo实现。(循环的算法不太懂)
* @param routeLine
* @param distance
* @return
*/
private ArrayList<LatLng divideRouteLine(ArrayList<LatLng routeLine, double distance) {
// 截取后的路线点的结果集
ArrayList<LatLng result = new ArrayList< ();
mNewTrafficTextureIndexList.clear();
for (int i = 0; i < routeLine.size() - 1; i++) {
final LatLng startPoint = routeLine.get(i);
final LatLng endPoint = routeLine.get(i + 1);
double slope = getSlope(startPoint, endPoint);
// 是不是正向的标示
boolean isYReverse = (startPoint.latitude endPoint.latitude);
boolean isXReverse = (startPoint.longitude endPoint.longitude);
double intercept = getInterception(slope, startPoint);
double xMoveDistance = isXReverse ? getXMoveDistance(slope, distance) :
-1 * getXMoveDistance(slope, distance);
double yMoveDistance = isYReverse ? getYMoveDistance(slope, distance) :
-1 * getYMoveDistance(slope, distance);
ArrayList<LatLng temp1 = new ArrayList< ();
for (double j = startPoint.latitude, k = startPoint.longitude;
!((j endPoint.latitude) ^ isYReverse) && !((k endPoint.longitude) ^ isXReverse); ) {
LatLng latLng = null;
if (slope == Double.MAX_VALUE) {
latLng = new LatLng(j, k);
j = j - yMoveDistance;
} else if (slope == 0.0) {
latLng = new LatLng(j, k - xMoveDistance);
k = k - xMoveDistance;
} else {
latLng = new LatLng(j, (j - intercept) / slope);
j = j - yMoveDistance;
}
final LatLng finalLatLng = latLng;
if (finalLatLng.latitude == 0 && finalLatLng.longitude == 0) {
continue;
}
mNewTrafficTextureIndexList.add(mTrafficTextureIndexList.get(i));
temp1.add(finalLatLng);
}
result.addAll(temp1);
if (i == routeLine.size() - 2) {
result.add(endPoint); // 终点
}
}
return result;
}
最后是开启子线程,对小车状态进行更新(车头方向和小车位置)
/**
* 循环进行移动逻辑
*/
public void moveLooper() {
moveThread = new Thread() {
public void run() {
Thread thisThread = Thread.currentThread();
while (!exit) {
for (int i = 0; i < latLngs.size() - 1; ) {
if (exit) {
break;
}
for (int p = 0; p < latLngs.size() - 1; p++) {
// 这是更新索引的条件,这里总是为true
// 实际情况可以是:当前误差小于5米 DistanceUtil.getDistance(mCurrentLatLng, latLngs.get(p)) <= 5)
// mCurrentLatLng 这个小车的当前位置得自行获取得到
if (true) {
// 实际情况的索引更新 mIndex = p;
mIndex++; // 模拟就是每次加1
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "当前索引:" + mIndex, Toast.LENGTH_SHORT).show();
}
});
break;
}
}
// 改变循环条件
i = mIndex + 1;
if (mIndex = latLngs.size() - 1) {
exit = true;
break;
}
// 擦除走过的路线
int len = mNewTrafficTextureIndexList.subList(mIndex, mNewTrafficTextureIndexList.size()).size();
Integer[] integers = mNewTrafficTextureIndexList.subList(mIndex, mNewTrafficTextureIndexList.size()).toArray(new Integer[len]);
int[] index = new int[integers.length];
for (int x = 0; x < integers.length; x++) {
index[x] = integers[x];
}
if (index.length 0) {
mPolyline.setIndexs(index);
mPolyline.setPoints(latLngs.subList(mIndex, latLngs.size()));
}
// 这里是小车的当前点和下一个点,用于确定车头方向
final LatLng startPoint = latLngs.get(mIndex);
final LatLng endPoint = latLngs.get(mIndex + 1);
mHandler.post(new Runnable() {
@Override
public void run() {
// 更新小车的位置和车头的角度
if (mMapView == null) {
return;
}
mMoveMarker.setPosition(startPoint);
mMoveMarker.setRotate((float) getAngle(startPoint,
endPoint));
}
});
try {
// 控制线程更新时间间隔
thisThread.sleep(TIME_INTERVAL);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
// 启动线程
moveThread.start();
}