文章目的
项目开发所需,所以结合百度地图提供的小车平滑轨迹移动,自己写的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 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 dividerouteline(arraylist routeline, double distance) {
// 截取后的路线点的结果集
arraylist 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 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();
}