package overlay;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import com.amap.api.maps.AMap;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.PolylineOptions;
import com.amap.api.services.busline.BusStationItem;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.route.BusPath;
import com.amap.api.services.route.BusStep;
import com.amap.api.services.route.Doorway;
import com.amap.api.services.route.RailwayStationItem;
import com.amap.api.services.route.RouteBusLineItem;
import com.amap.api.services.route.RouteBusWalkItem;
import com.amap.api.services.route.RouteRailwayItem;
import com.amap.api.services.route.TaxiItem;
import com.amap.api.services.route.WalkStep;
import com.sd.maplibrary.utils.amp.AMapUtil;
/**
* 公交路线图层类。在高德地图API里,如果需要显示公交路线,可以用此类来创建公交路线图层。如不满足需求,也可以自己创建自定义的公交路线图层。
* @since V2.1.0
*/
public class BusRouteOverlay extends RouteOverlay {
private BusPath busPath;
private LatLng latLng;
/**
* 通过此构造函数创建公交路线图层。
* @param context 当前activity。
* @param amap 地图对象。
* @param path 公交路径规划的一个路段。详见搜索服务模块的路径查询包(com.amap.api.services.route)中的类 BusPath。
* @param start 起点坐标。详见搜索服务模块的核心基础包(com.amap.api.services.core)中的类 LatLonPoint。
* @param end 终点坐标。详见搜索服务模块的核心基础包(com.amap.api.services.core)中的类 LatLonPoint。
* @since V2.1.0
*/
public BusRouteOverlay(Context context, AMap amap, BusPath path,
LatLonPoint start, LatLonPoint end) {
super(context);
this.busPath = path;
startPoint = AMapUtil.convertToLatLng(start);
endPoint = AMapUtil.convertToLatLng(end);
mAMap = amap;
}
/**
* 添加公交路线到地图上。
* @since V2.1.0
*/
public void addToMap() {
/**
* 绘制节点和线
* 细节情况较多
* 两个step之间,用step和step1区分
* 1.一个step内可能有步行和公交,然后有可能他们之间连接有断开
* 2.step的公交和step1的步行,有可能连接有断开
* 3.step和step1之间是公交换乘,且没有步行,需要把step的终点和step1的起点连起来
* 4.公交最后一站和终点间有步行,加入步行线路,还会有一些步行marker
* 5.公交最后一站和终点间无步行,之间连起来
*/
try {
List busSteps = busPath.getSteps();
for (int i = 0; i < busSteps.size(); i++) {
BusStep busStep = busSteps.get(i);
if (i < busSteps.size() - 1) {
BusStep busStep1 = busSteps.get(i + 1);// 取得当前下一个BusStep对象
// 假如步行和公交之间连接有断开,就把步行最后一个经纬度点和公交第一个经纬度点连接起来,避免断线问题
if (busStep.getWalk() != null
&& busStep.getBusLine() != null) {
checkWalkToBusline(busStep);
}
// 假如公交和步行之间连接有断开,就把上一公交经纬度点和下一步行第一个经纬度点连接起来,避免断线问题
if (busStep.getBusLine() != null
&& busStep1.getWalk() != null
&& busStep1.getWalk().getSteps().size() > 0) {
checkBusLineToNextWalk(busStep, busStep1);
}
// 假如两个公交换乘中间没有步行,就把上一公交经纬度点和下一步公交第一个经纬度点连接起来,避免断线问题
if (busStep.getBusLine() != null
&& busStep1.getWalk() == null
&& busStep1.getBusLine() != null) {
checkBusEndToNextBusStart(busStep, busStep1);
}
// 和上面的很类似
if (busStep.getBusLine() != null
&& busStep1.getWalk() == null
&& busStep1.getBusLine() != null) {
checkBusToNextBusNoWalk(busStep, busStep1);
}
if (busStep.getBusLine() != null
&& busStep1.getRailway() != null ) {
checkBusLineToNextRailway(busStep, busStep1);
}
if (busStep1.getWalk() != null &&
busStep1.getWalk().getSteps().size() > 0 &&
busStep.getRailway() != null) {
checkRailwayToNextWalk(busStep, busStep1);
}
if ( busStep1.getRailway() != null &&
busStep.getRailway() != null) {
checkRailwayToNextRailway(busStep, busStep1);
}
if (busStep.getRailway() != null &&
busStep1.getTaxi() != null ){
checkRailwayToNextTaxi(busStep, busStep1);
}
}
if (busStep.getWalk() != null
&& busStep.getWalk().getSteps().size() > 0) {
addWalkSteps(busStep);
} else {
if (busStep.getBusLine() == null && busStep.getRailway() == null && busStep.getTaxi() == null) {
addWalkPolyline(latLng, endPoint);
}
}
if (busStep.getBusLine() != null) {
RouteBusLineItem routeBusLineItem = busStep.getBusLine();
addBusLineSteps(routeBusLineItem);
addBusStationMarkers(routeBusLineItem);
if (i == busSteps.size() - 1) {
addWalkPolyline(AMapUtil.convertToLatLng(getLastBuslinePoint(busStep)), endPoint);
}
}
if (busStep.getRailway() != null) {
addRailwayStep(busStep.getRailway());
addRailwayMarkers(busStep.getRailway());
if (i == busSteps.size() - 1) {
addWalkPolyline(AMapUtil.convertToLatLng(busStep.getRailway().getArrivalstop().getLocation()), endPoint);
}
}
if (busStep.getTaxi() != null) {
addTaxiStep(busStep.getTaxi());
addTaxiMarkers(busStep.getTaxi());
}
}
addStartAndEndMarker();
} catch (Throwable e) {
e.printStackTrace();
}
}
private void checkRailwayToNextTaxi(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint taxiFirstPoint = busStep1.getTaxi().getOrigin();
if (!railwayLastPoint.equals(taxiFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, taxiFirstPoint);
}
}
private void checkRailwayToNextRailway(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint railwayFirstPoint = busStep1.getRailway().getDeparturestop().getLocation();
if (!railwayLastPoint.equals(railwayFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, railwayFirstPoint);
}
}
private void checkBusLineToNextRailway(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLonPoint railwayFirstPoint = busStep1.getRailway().getDeparturestop().getLocation();
if (!busLastPoint.equals(railwayFirstPoint)) {
addWalkPolyLineByLatLonPoints(busLastPoint, railwayFirstPoint);
}
}
private void checkRailwayToNextWalk(BusStep busStep, BusStep busStep1) {
LatLonPoint railwayLastPoint = busStep.getRailway().getArrivalstop().getLocation();
LatLonPoint walkFirstPoint = getFirstWalkPoint(busStep1);
if (!railwayLastPoint.equals(walkFirstPoint)) {
addWalkPolyLineByLatLonPoints(railwayLastPoint, walkFirstPoint);
}
}
private void addRailwayStep(RouteRailwayItem railway) {
List railwaylistpoint = new ArrayList();
List railwayStationItems = new ArrayList();
railwayStationItems.add(railway.getDeparturestop());
railwayStationItems.addAll(railway.getViastops());
railwayStationItems.add(railway.getArrivalstop());
for (int i = 0; i < railwayStationItems.size(); i++) {
railwaylistpoint.add(AMapUtil.convertToLatLng(railwayStationItems.get(i).getLocation()));
}
addRailwayPolyline(railwaylistpoint);
}
private void addTaxiStep(TaxiItem taxi){
addPolyLine(new PolylineOptions().width(getRouteWidth())
.color(getBusColor())
.add(AMapUtil.convertToLatLng(taxi.getOrigin()))
.add(AMapUtil.convertToLatLng(taxi.getDestination())));
}
/**
* @param busStep
*/
private void addWalkSteps(BusStep busStep) {
RouteBusWalkItem routeBusWalkItem = busStep.getWalk();
List walkSteps = routeBusWalkItem.getSteps();
for (int j = 0; j < walkSteps.size(); j++) {
WalkStep walkStep = walkSteps.get(j);
if (j == 0) {
LatLng latLng = AMapUtil.convertToLatLng(walkStep
.getPolyline().get(0));
String road = walkStep.getRoad();// 道路名字
String instruction = getWalkSnippet(walkSteps);// 步行导航信息
addWalkStationMarkers(latLng, road, instruction);
}
List listWalkPolyline = AMapUtil
.convertArrList(walkStep.getPolyline());
this.latLng = listWalkPolyline.get(listWalkPolyline.size() - 1);
addWalkPolyline(listWalkPolyline);
// 假如步行前一段的终点和下的起点有断开,断画直线连接起来,避免断线问题
if (j < walkSteps.size() - 1) {
LatLng lastLatLng = listWalkPolyline.get(listWalkPolyline
.size() - 1);
LatLng firstlatLatLng = AMapUtil
.convertToLatLng(walkSteps.get(j + 1).getPolyline()
.get(0));
if (!(lastLatLng.equals(firstlatLatLng))) {
addWalkPolyline(lastLatLng, firstlatLatLng);
}
}
}
}
/**
* 添加一系列的bus PolyLine
*
* @param routeBusLineItem
*/
private void addBusLineSteps(RouteBusLineItem routeBusLineItem) {
addBusLineSteps(routeBusLineItem.getPolyline());
}
private void addBusLineSteps(List listPoints) {
if (listPoints.size() < 1) {
return;
}
addPolyLine(new PolylineOptions().width(getRouteWidth())
.color(getBusColor())
.addAll(AMapUtil.convertArrList(listPoints)));
}
/**
* @param latLng
* marker
* @param title
* @param snippet
*/
private void addWalkStationMarkers(LatLng latLng, String title,
String snippet) {
addStationMarker(new MarkerOptions().position(latLng).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getWalkBitmapDescriptor()));
}
/**
* @param routeBusLineItem
*/
private void addBusStationMarkers(RouteBusLineItem routeBusLineItem) {
BusStationItem startBusStation = routeBusLineItem
.getDepartureBusStation();
LatLng position = AMapUtil.convertToLatLng(startBusStation
.getLatLonPoint());
String title = routeBusLineItem.getBusLineName();
String snippet = getBusSnippet(routeBusLineItem);
addStationMarker(new MarkerOptions().position(position).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
}
private void addTaxiMarkers(TaxiItem taxiItem) {
LatLng position = AMapUtil.convertToLatLng(taxiItem
.getOrigin());
String title = taxiItem.getmSname()+"打车";
String snippet = "到终点";
addStationMarker(new MarkerOptions().position(position).title(title)
.snippet(snippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getDriveBitmapDescriptor()));
}
private void addRailwayMarkers(RouteRailwayItem railway) {
LatLng Departureposition = AMapUtil.convertToLatLng(railway
.getDeparturestop().getLocation());
String Departuretitle = railway.getDeparturestop().getName()+"上车";
String Departuresnippet = railway.getName();
addStationMarker(new MarkerOptions().position(Departureposition).title(Departuretitle)
.snippet(Departuresnippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
LatLng Arrivalposition = AMapUtil.convertToLatLng(railway
.getArrivalstop().getLocation());
String Arrivaltitle = railway.getArrivalstop().getName()+"下车";
String Arrivalsnippet = railway.getName();
addStationMarker(new MarkerOptions().position(Arrivalposition).title(Arrivaltitle)
.snippet(Arrivalsnippet).anchor(0.5f, 0.5f).visible(nodeIconVisible)
.icon(getBusBitmapDescriptor()));
}
/**
* 如果换乘没有步行 检查bus最后一点和下一个step的bus起点是否一致
*
* @param busStep
* @param busStep1
*/
private void checkBusToNextBusNoWalk(BusStep busStep, BusStep busStep1) {
LatLng endbusLatLng = AMapUtil
.convertToLatLng(getLastBuslinePoint(busStep));
LatLng startbusLatLng = AMapUtil
.convertToLatLng(getFirstBuslinePoint(busStep1));
if (startbusLatLng.latitude - endbusLatLng.latitude > 0.0001
|| startbusLatLng.longitude - endbusLatLng.longitude > 0.0001) {
drawLineArrow(endbusLatLng, startbusLatLng);// 断线用带箭头的直线连?
}
}
/**
*
* checkBusToNextBusNoWalk 和这个类似
*
* @param busStep
* @param busStep1
*/
private void checkBusEndToNextBusStart(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLng endbusLatLng = AMapUtil.convertToLatLng(busLastPoint);
LatLonPoint busFirstPoint = getFirstBuslinePoint(busStep1);
LatLng startbusLatLng = AMapUtil.convertToLatLng(busFirstPoint);
if (!endbusLatLng.equals(startbusLatLng)) {
drawLineArrow(endbusLatLng, startbusLatLng);//
}
}
/**
* 检查bus最后一步和下一各step的步行起点是否一致
*
* @param busStep
* @param busStep1
*/
private void checkBusLineToNextWalk(BusStep busStep, BusStep busStep1) {
LatLonPoint busLastPoint = getLastBuslinePoint(busStep);
LatLonPoint walkFirstPoint = getFirstWalkPoint(busStep1);
if (!busLastPoint.equals(walkFirstPoint)) {
addWalkPolyLineByLatLonPoints(busLastPoint, walkFirstPoint);
}
}
/**
* 检查 步行最后一点 和 bus的起点 是否一致
*
* @param busStep
*/
private void checkWalkToBusline(BusStep busStep) {
LatLonPoint walkLastPoint = getLastWalkPoint(busStep);
LatLonPoint buslineFirstPoint = getFirstBuslinePoint(busStep);
if (!walkLastPoint.equals(buslineFirstPoint)) {
addWalkPolyLineByLatLonPoints(walkLastPoint, buslineFirstPoint);
}
}
/**
* @param busStep1
* @return
*/
private LatLonPoint getFirstWalkPoint(BusStep busStep1) {
return busStep1.getWalk().getSteps().get(0).getPolyline().get(0);
}
/**
*
*/
private void addWalkPolyLineByLatLonPoints(LatLonPoint pointFrom,
LatLonPoint pointTo) {
LatLng latLngFrom = AMapUtil.convertToLatLng(pointFrom);
LatLng latLngTo = AMapUtil.convertToLatLng(pointTo);
addWalkPolyline(latLngFrom, latLngTo);
}
/**
* @param latLngFrom
* @param latLngTo
* @return
*/
private void addWalkPolyline(LatLng latLngFrom, LatLng latLngTo) {
addPolyLine(new PolylineOptions().add(latLngFrom, latLngTo)
.width(getRouteWidth()).color(getWalkColor()).setDottedLine(true));
}
/**
* @param listWalkPolyline
*/
private void addWalkPolyline(List listWalkPolyline) {
addPolyLine(new PolylineOptions().addAll(listWalkPolyline)
.color(getWalkColor()).width(getRouteWidth()).setDottedLine(true));
}
private void addRailwayPolyline(List listPolyline) {
addPolyLine(new PolylineOptions().addAll(listPolyline)
.color(getDriveColor()).width(getRouteWidth()));
}
private String getWalkSnippet(List walkSteps) {
float disNum = 0;
for (WalkStep step : walkSteps) {
disNum += step.getDistance();
}
return "\u6B65\u884C" + disNum + "\u7C73";
}
public void drawLineArrow(LatLng latLngFrom, LatLng latLngTo) {
addPolyLine(new PolylineOptions().add(latLngFrom, latLngTo).width(3)
.color(getBusColor()).width(getRouteWidth()));// 绘制直线
}
private String getBusSnippet(RouteBusLineItem routeBusLineItem) {
return "("
+ routeBusLineItem.getDepartureBusStation().getBusStationName()
+ "-->"
+ routeBusLineItem.getArrivalBusStation().getBusStationName()
+ ") \u7ECF\u8FC7" + (routeBusLineItem.getPassStationNum() + 1)
+ "\u7AD9";
}
/**
* @param busStep
* @return
*/
private LatLonPoint getLastWalkPoint(BusStep busStep) {
List walkSteps = busStep.getWalk().getSteps();
WalkStep walkStep = walkSteps.get(walkSteps.size() - 1);
List lonPoints = walkStep.getPolyline();
return lonPoints.get(lonPoints.size() - 1);
}
private LatLonPoint getExitPoint(BusStep busStep) {
Doorway doorway = busStep.getExit();
if (doorway == null) {
return null;
}
return doorway.getLatLonPoint();
}
private LatLonPoint getLastBuslinePoint(BusStep busStep) {
List lonPoints = busStep.getBusLine().getPolyline();
return lonPoints.get(lonPoints.size() - 1);
}
private LatLonPoint getEntrancePoint(BusStep busStep) {
Doorway doorway = busStep.getEntrance();
if (doorway == null) {
return null;
}
return doorway.getLatLonPoint();
}
private LatLonPoint getFirstBuslinePoint(BusStep busStep) {
return busStep.getBusLine().getPolyline().get(0);
}
}