仿滴滴打车 车辆运动

因工作需要, 写了一份类似于滴滴打车 车辆运动的 demo;

功能:1.可以实现车辆位移变化及车辆车头转向;2.集成了百度地图;实现了地理坐标反取;

代码:
MapActivity.class

package com.example.dididache;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Toast;

import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BaiduMap.OnMapStatusChangeListener;
import com.baidu.mapapi.map.BaiduMap.OnMarkerDragListener;
import com.baidu.mapapi.map.BitmapDescriptor;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.MapStatus;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;

public class MapActivity extends Activity implements OnGetGeoCoderResultListener, OnClickListener {
private MapView mMapView = null;
private GeoCoder mSearch = null;
private BaiduMap mBaiduMap = null;
private Marker carMarker;
private BitmapDescriptor bdA;
private MarkerOptions ooA;

private LatLng latlng0 = new LatLng(39.977552, 116.320331); // 人民大学;左上
private LatLng latlng1 = new LatLng(39.977552, 116.460036); // 香河园街道 右上
private LatLng latlng2 = new LatLng(39.855805, 116.320331); // 左下
private LatLng latlng3 = new LatLng(39.855805, 116.460036); // 右下;

private List<LatLng> latlngsTop = new ArrayList<LatLng>();
private List<LatLng> latlngsLeft = new ArrayList<LatLng>();
private List<LatLng> latlngsRight = new ArrayList<LatLng>();
private List<LatLng> latlngsBottom = new ArrayList<LatLng>();

private CarRunInfo carInfo;
private Thread t;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    SDKInitializer.initialize(getApplicationContext());
    setContentView(R.layout.activity_main);
    mMapView = (MapView) findViewById(R.id.bmapView);

    findViewById(R.id.btn_car_run).setOnClickListener(this);
    bdA = BitmapDescriptorFactory.fromResource(R.drawable.xiaoche1);

    mBaiduMap = mMapView.getMap();
    MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(12.0f);
    mBaiduMap.setMapStatus(msu);

    mSearch = GeoCoder.newInstance();
    mSearch.setOnGetGeoCodeResultListener(this);
    mBaiduMap.setOnMapStatusChangeListener(new OnMapStatusChangeListener() {

        @Override
        public void onMapStatusChangeStart(MapStatus arg0) {

        }

        @Override
        public void onMapStatusChangeFinish(MapStatus arg0) {
            LatLng ptCenter = mBaiduMap.getMapStatus().target;
            mSearch.reverseGeoCode(new ReverseGeoCodeOption().location(ptCenter));
        }

        @Override
        public void onMapStatusChange(MapStatus arg0) {

        }
    });
    initOverlay();
    initCarInfo();
    getPointData();
}

private void initCarInfo() {
    carInfo = new CarRunInfo();
}

/**
 * 服务器返回 车辆的 实时坐标。
 */
private void getPointData() {
    latlngsTop = computEdgepoints(latlng0, latlng1, latlngsTop, Edge.Top);
    latlngsLeft = computEdgepoints(latlng0, latlng2, latlngsLeft, Edge.Left);
    latlngsRight = computEdgepoints(latlng1, latlng3, latlngsRight, Edge.Right);
    latlngsBottom = computEdgepoints(latlng2, latlng3, latlngsBottom, Edge.Bottom);
}

enum Edge {
    Top, Left, Right, Bottom;
}

/**
 * 计算添加模拟数据;
 * 
 * @param latlng1
 * @param latlng2
 * @param latlngs
 * @param edge
 * @return
 */
public List<LatLng> computEdgepoints(LatLng latlng1, LatLng latlng2, List<LatLng> latlngs, Edge edge) {
    // 每边采集300个点,每秒采集10个点;
    double distance = 0;

    if (edge == Edge.Top) {
        distance = latlng2.longitude - latlng1.longitude;
        for (int i = 0; i < 300; i++) {
            latlngs.add(new LatLng(latlng1.latitude, latlng1.longitude + (i + 1) * (distance / 300)));
        }
    } else if (edge == Edge.Left) {
        distance = latlng1.latitude - latlng2.latitude;
        for (int i = 0; i < 300; i++) {
            latlngs.add(new LatLng(latlng2.latitude + (i + 1) * (distance / 300), latlng2.longitude));
        }
    } else if (edge == Edge.Right) {
        distance = latlng2.latitude - latlng1.latitude;
        for (int i = 0; i < 300; i++) {
            latlngs.add(new LatLng(latlng1.latitude + (i + 1) * (distance / 300), latlng2.longitude));
        }
    } else if (edge == Edge.Bottom) {
        distance = latlng1.longitude - latlng2.longitude;
        for (int i = 0; i < 300; i++) {
            latlngs.add(new LatLng(latlng1.latitude, latlng2.longitude + (i + 1) * (distance / 300)));
        }
    }

    return latlngs;

}

/**
 * 转向
 * 
 * @param latlng1
 * @param latlng2
 * @param carMarker
 * @param errorRange
 *            误差范围, 大于 errorRange 值 可视为 转向有效值;
 */
public void changeCarOrientation(LatLng latlng1, LatLng latlng2, Marker carMarker, double errorRange) {

    if (latlng1.latitude == latlng2.latitude && latlng1.longitude == latlng2.longitude) {

    } else {

        // 获取下一个车头朝向;
        double nextOrientation = getNextOrientation(latlng1, latlng2);
        // 获取当前车头朝向;
        double currentAngle = carInfo.getAngle();
        // 逆时针 角度为负值;
        if (Math.abs(nextOrientation - currentAngle) > errorRange) {
            carInfo.setAngle(nextOrientation);
            System.out.println("nextOrientation:" + nextOrientation + ",currentAngle:" + currentAngle);
            float computAngle = (float) computRotateAngle(currentAngle, nextOrientation);
            carMarker.setRotate(carMarker.getRotate() + computAngle);// 逆时针;
            System.out.println("computAngle:" + computAngle);
        }
    }
}

// 负值--顺时针旋转;
private double computRotateAngle(double currentAngle, double nextAngle) {

    return nextAngle - currentAngle;

}

/**
 * 获取下一个车的方向;
 * 
 * @param latlng1
 * @param latlng2
 * @return
 */
public double getNextOrientation(LatLng latlng1, LatLng latlng2) {
    double angle;
    // 求出三边边长;
    double a, b, c, a1, b1;

    a1 = latlng2.latitude - latlng1.latitude;
    b1 = latlng2.longitude - latlng1.longitude;

    double latitudeDif = Math.abs(a1);
    double longitudeDif = Math.abs(b1);
    a = latitudeDif;// 纬度;
    b = longitudeDif;
    c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
    if (a == 0) {
        // 车头朝向 0或 180;
        // 纬度共有90度。赤道为0度,向两极排列,圈子越小,度数越大。
        if ((latlng2.longitude - latlng1.longitude) < 0) {// 经度;
            angle = 180;
        } else {
            angle = 0;
        }
    } else if (b == 0) {
        if ((latlng2.latitude - latlng1.latitude) < 0) {// 纬度;
            angle = 270;
        } else {
            angle = 90;
        }
    } else {
        System.out.println("a1:" + a1 + ",b1:" + b1);
        System.out.println((a1 > 0) + "," + (b1 > 0));

        angle = Math.toDegrees(Math.acos(b / c));
        if (a1 < 0 && b1 > 0) {
            angle = 360 - angle;
        } else if (a1 > 0 && b1 > 0) {

        } else if (a1 > 0 && b1 < 0) {
            angle = 180 - angle;
        } else if (a1 < 0 && b1 < 0) {
            angle = 180 + angle;

        }

    }
    return angle;
}

private boolean isRun = false;

public void carRun() {
    if (!isRun) {
        t = new Thread(new Runnable() {
            @Override
            public void run() {
                isRun = true;
                SystemClock.sleep(200);
                runPoints(latlngsTop);
                runPoints(latlngsRight);
                runPoints(latlngsBottom);
                runPoints(latlngsLeft);
                isRun = false;
            }

        });
        t.start();
    }
}

private void runPoints(List<LatLng> latlngs) {
    try {
        for (int i = 0; i < latlngs.size(); i++) {
            Thread.sleep(50);
            changeCarPosition(latlngs, i);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

/**
 * 改变车辆位移及朝向
 * 
 * @param latlngs
 * @param i
 */
private void changeCarPosition(List<LatLng> latlngs, int i) {
    if (i < latlngs.size() - 1) {
        changeCarOrientation(latlngs.get(i), latlngs.get(i + 1), carMarker, 2);
    }
    carMarker.setPosition(latlngs.get(i));
}

@Override
public void onGetGeoCodeResult(GeoCodeResult result) {
    MapStatusUpdate status = MapStatusUpdateFactory.newLatLng(result.getLocation());
    mBaiduMap.animateMapStatus(status);
    Toast.makeText(MapActivity.this, result.getAddress(), Toast.LENGTH_LONG).show();
}

@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
    if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
        Toast.makeText(MapActivity.this, "unknow", Toast.LENGTH_LONG).show();
        return;
    }
    mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result.getLocation()));
    Toast.makeText(MapActivity.this, result.getAddressDetail().city + "  " + result.getAddressDetail().district + "  " + result.getAddressDetail().street + result.getAddressDetail().streetNumber,
            Toast.LENGTH_LONG).show();

}

public void initOverlay() {
    // add marker overlay
    LatLng llA = new LatLng(latlng0.latitude, latlng0.longitude);

    ooA = new MarkerOptions().position(llA).icon(bdA).zIndex(9).draggable(false);
    carMarker = (Marker) (mBaiduMap.addOverlay(ooA));

    mBaiduMap.setOnMarkerDragListener(new OnMarkerDragListener() {
        public void onMarkerDrag(Marker marker) {
        }

        public void onMarkerDragEnd(Marker marker) {
            Toast.makeText(MapActivity.this, "拖拽结束,新位置:" + marker.getPosition().latitude + ", " + marker.getPosition().longitude, Toast.LENGTH_LONG).show();
        }

        public void onMarkerDragStart(Marker marker) {
        }
    });

}

@Override
public void onClick(View v) {
    carRun();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mMapView.onDestroy();
}

@Override
protected void onResume() {
    super.onResume();
    mMapView.onResume();
}

@Override
protected void onPause() {
    super.onPause();
    mMapView.onPause();
}

}

//还有一个车辆信息bean;CarRunInfo.class

package com.example.dididache;

import com.baidu.mapapi.model.LatLng;

public class CarRunInfo {

private LatLng carPosition = new LatLng(39.977552, 116.320331);
private double angle = 270;

public LatLng getCarPosition() {
    return carPosition;
}

public void setCarPosition(LatLng carPosition) {
    this.carPosition = carPosition;
}

public double getAngle() {
    return angle;
}

public void setAngle(double angle) {
    this.angle = angle;
}

}

猜你喜欢

转载自blog.csdn.net/qq_17827919/article/details/52085907