zoukankan      html  css  js  c++  java
  • 道格拉斯轨迹抽稀算法Android 百度地图SDK

    参考博客

    https://blog.csdn.net/qq_28602957/article/details/89339944
    https://blog.csdn.net/weixin_34190136/article/details/91752983
    https://blog.csdn.net/c10WTiybQ1Ye3/article/details/78126082

    参考开发文档

    http://lbsyun.baidu.com/index.php?title=androidsdk

    实现效果

    抽稀前:
    在这里插入图片描述
    抽稀后:
    在这里插入图片描述
    算法的详细原理请参考1、2两篇文献

    抽析代码

    public class DouglasPeuckerUtil {
    
        public static List<LatLng> DouglasPeucker(List<LatLng> points ,int epsilon) {
            double maxH = 0 ;
            int index = 0;
            int end = points.size();
            for (int i = 1; i < end - 1; i++){
                double h = H(points.get(0),points.get(i),points.get(end-1));
                if(h > maxH){
                    maxH = h;
                    index = i;
                }
            }
            List<LatLng> result = new ArrayList<>();
            if (maxH > epsilon){
                List<LatLng> leftPoints = new ArrayList<>();//左曲线
                List<LatLng> rightPoints = new ArrayList<>();//右曲线
                //分别保存左曲线和右曲线的坐标点
                for (int i = 0; i < end; i++){
                    if (i <= index){
                        leftPoints.add(points.get(i));
                        if (i == index){
                            rightPoints.add(points.get(i));
                        }
                    }else{
                        rightPoints.add(points.get(i));
                    }
                }
                List<LatLng>leftResult = new ArrayList<>();
                List<LatLng>rightResult = new ArrayList<>();
                leftResult = DouglasPeucker(leftPoints,epsilon);
                rightResult = DouglasPeucker(rightPoints,epsilon);
    
                rightResult.remove(0);//移除重复的点
                leftResult.addAll(rightResult);
                result = leftResult;
            }else {
                result.add(points.get(0));
                result.add(points.get(end - 1));
            }
            return result;
        }
    
        public static double H (LatLng A, LatLng B, LatLng C){
            double c = DistanceUtil.getDistance(A,B);
    
            double b = DistanceUtil.getDistance(A,C);
    
            double a = DistanceUtil.getDistance(C,B);
    
            double S = helen(a,b,c);
    
            double H = 2 * S / c;
    
            return H;
        }
    
        public static double helen(double a,double b,double c){
            double p = (a + b + c)/2;
            double S = Math.sqrt(p * (p - a) * (p - b) * (p - c));
            return S;
        }
    }
    

    MainActivity

    package com.example.tracksparsetest;
    
    import androidx.annotation.NonNull;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.app.ActivityCompat;
    import androidx.core.content.ContextCompat;
    
    import android.Manifest;
    import android.app.ProgressDialog;
    import android.content.pm.PackageManager;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.baidu.location.BDAbstractLocationListener;
    import com.baidu.location.BDLocation;
    import com.baidu.location.LocationClient;
    import com.baidu.location.LocationClientOption;
    import com.baidu.mapapi.CoordType;
    import com.baidu.mapapi.SDKInitializer;
    import com.baidu.mapapi.map.BaiduMap;
    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.MarkerOptions;
    import com.baidu.mapapi.map.MyLocationConfiguration;
    import com.baidu.mapapi.map.MyLocationData;
    import com.baidu.mapapi.map.Overlay;
    import com.baidu.mapapi.map.OverlayOptions;
    import com.baidu.mapapi.map.Polyline;
    import com.baidu.mapapi.map.PolylineOptions;
    import com.baidu.mapapi.model.LatLng;
    import com.baidu.mapapi.utils.DistanceUtil;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
    //    //始点图层图标
    //    private BitmapDescriptor startBD = BitmapDescriptorFactory
    //            .fromResource(R.drawable.ic_start);
    //    //终点图层图标
    //    private BitmapDescriptor finishBD = BitmapDescriptorFactory
    //            .fromResource(R.drawable.ic_stop);
    
        public LocationClient mlocationClient;
    
        public MapView mMapView = null;
    
        private TextView positionText;
    
        private BaiduMap mBaiduMap;
    
        private boolean isFirstLocate = true;
    
        private float mCurrentZoom =16f;
    
        private LatLng lastPoint;//记录上一个定位点
    
        private Overlay mPolyline;
    
        private double mCurrentLat;
    
        private double mCurrentLon;
    
        private float mCurrentDirection;
    
        private MapStatus.Builder builder;
    
        private MyLocationData locData;
    
        private Button start;
    
        private Button finish;
    
        private ProgressDialog progressDialog;
    
    //    List<OverlayOptions> markers = new ArrayList<>();
    
        List<LatLng> points = new ArrayList<LatLng>();
    
        List<LatLng> points_Sparsed = new ArrayList<LatLng>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //在使用SDK各组件之前初始化context信息,传入ApplicationContext
            SDKInitializer.initialize(getApplicationContext());//this报错
            //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型.
            //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。
            SDKInitializer.setCoordType(CoordType.BD09LL);
            mlocationClient = new LocationClient(getApplicationContext());
            mlocationClient.registerLocationListener(new MyLocationListener());
            initLocation();
            setContentView(R.layout.activity_main);
            start = (Button) findViewById(R.id.start_b);
            finish = (Button)findViewById(R.id.finish_b);
            positionText = (TextView)findViewById(R.id.position_text_view);
            mMapView = (MapView)findViewById(R.id.bmapView);
            mBaiduMap = mMapView.getMap();
            mBaiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE);
            //开启地图定位图层
            mBaiduMap.setMyLocationEnabled(true);
    
            /**添加地图缩放状态变化监听,当手动放大或缩小地图时,拿到缩放后的比例,然后获取到下次定位,
             *  给地图重新设置缩放比例,否则地图会重新回到默认的mCurrentZoom缩放比例
             */
            mCurrentZoom = 20;
    
            mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
                @Override
                public void onMapStatusChangeStart(MapStatus mapStatus) {
    
                }
    
                @Override
                public void onMapStatusChangeStart(MapStatus mapStatus, int i) {
    
                }
    
                @Override
                public void onMapStatusChange(MapStatus mapStatus) {
    
                }
    
                @Override
                public void onMapStatusChangeFinish(MapStatus mapStatus) {
                    mCurrentZoom = mapStatus.zoom;
                }
            });
    
            //设置定位图标类型为跟随模式
            mBaiduMap.setMyLocationConfiguration(new MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING,true,null));
    
            //运行时权限检查
            List<String> permissionList = new ArrayList<>();
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
                permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
            }
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED){
                permissionList.add(Manifest.permission.READ_PHONE_STATE);
            }
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
                permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if (!permissionList.isEmpty()){
                String[] permissions = permissionList.toArray(new String[permissionList.size()]);
                ActivityCompat.requestPermissions(MainActivity.this,permissions,1);
            }else {
                requestLocation();
            }
        }
    
        private void requestLocation(){
    //        initLocation();
    //        mlocationClient.start();
            start.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mlocationClient.start();
    //                progressDialog = new ProgressDialog(MainActivity.this);
    //                progressDialog.setTitle("搜索GPS中");
    //                progressDialog.setMessage("....");
    //                progressDialog.setCancelable(true);
    //                progressDialog.show();
                }
            });
            finish.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (mlocationClient != null && mlocationClient.isStarted()) {
                        mlocationClient.stop();//停止定位
    
                        if(points.size() <= 0){
                            return;
                        }
    
                        //运动结束记得标记终点图标
                        MarkerOptions oFinish = new MarkerOptions();
                        oFinish.position(points.get(points.size() - 1));
                        BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.ic_stop);
                        oFinish.icon(bitmap);
                        mBaiduMap.addOverlay(oFinish);
                    }
                }
            });
    
        }
    
        private void initLocation(){
            LocationClientOption option = new LocationClientOption();
            option.setScanSpan(1000);
            option.setCoorType("bd09ll");
            option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
            mlocationClient.setLocOption(option);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            switch (requestCode){
                case 1:
                    if (grantResults.length > 0){
                        for (int result : grantResults){
                            if (result != PackageManager.PERMISSION_GRANTED){
                                Toast.makeText(this,"必须同意所有权限才能使用",Toast.LENGTH_SHORT).show();
                                finish();
                                return;
                            }
                        }
                        //
                        requestLocation();
                    }else {
                        Toast.makeText(this,"发生未知错误",Toast.LENGTH_SHORT).show();
                        finish();
                    }
                    break;
                default:
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mMapView.onResume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            mMapView.onPause();
        }
    
        @Override
        protected void onDestroy() {
            // 退出时销毁定位
    //        mlocationClient.unRegisterLocationListener(myListener);
            mlocationClient.stop();
            mBaiduMap.setMyLocationEnabled(false);
            mMapView.onDestroy();
            mMapView = null;
    //        startBD.recycle();
    //        finishBD.recycle();
            super.onDestroy();
        }
    
        private void navigateTo(BDLocation bdLocation){
            if (isFirstLocate){
                LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
                MapStatusUpdate update = MapStatusUpdateFactory.newLatLng(ll);
                mBaiduMap.animateMapStatus(update);
                update = MapStatusUpdateFactory.zoomTo(16f);
                mBaiduMap.animateMapStatus(update);
                isFirstLocate = false;
            }
            if (bdLocation == null || mMapView == null){
                return;
            }
            MyLocationData locData1 = new MyLocationData.Builder()
                    .accuracy(bdLocation.getRadius())
                    .direction(bdLocation.getDirection())
                    .latitude(bdLocation.getLatitude())
                    .longitude(bdLocation.getLongitude())
                    .build();
            mBaiduMap.setMyLocationData(locData1);
        }
    
        public class MyLocationListener extends BDAbstractLocationListener {
    
            @Override
            public void onReceiveLocation(final BDLocation bdLocation) {
    //            LatLng l = getMostAccuracyLocation(bdLocation);
    //            locateAndZoom(bdLocation,l);
    //            navigateTo(bdLocation);
    //            drawPoint(bdLocation);
    //            drawLine(bdLocation);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
    
                        StringBuilder currentPosition = new StringBuilder();
                        currentPosition.append("纬度:").append(bdLocation.getLatitude()).append("
    ");
                        currentPosition.append("经线:").append(bdLocation.getLongitude()).append("
    ");
                        currentPosition.append("定位方式");
                        if (bdLocation.getLocType() == BDLocation.TypeGpsLocation){
                            currentPosition.append("GPS "+"|抽稀后:"+ points_Sparsed.size()+"|抽稀前:"+points.size());
                        }else if (bdLocation.getLocType() == BDLocation.TypeNetWorkLocation){
                            currentPosition.append("netWork"+"|抽稀后:"+ points_Sparsed.size()+"|抽稀前:"+points.size());
                        }
                        positionText.setText(currentPosition);
    
                    }
                });
                if ((bdLocation.getLocType() == BDLocation.TypeGpsLocation)){
                    if (isFirstLocate){
                        LatLng ll = null;
                        ll = getMostAccuracyLocation(bdLocation);
    //                    ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
    //                    progressDialog.dismiss();
    //                    Log.d("onReceiveLocation1",  ll.toString());
                        if (ll == null){
                            return;
                        }
                        isFirstLocate = false;
                        points.add(ll);//加入集合
    //                    points_Sparsed = DouglasPeuckerUtil.DouglasPeucker(points,1);
                        lastPoint = ll;//记录上一个点
    
                        //显示当前定位点,缩放地图
                        locateAndZoom(bdLocation,ll);
    
                        BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.ic_start);
                        OverlayOptions oStart = new MarkerOptions()
                                .position(points.get(0))
                                .icon(bitmap);//地图标记覆盖物参数配置;
                        mBaiduMap.addOverlay(oStart);
                        return;//画轨迹至少两个点,这里返回
                    }
    //                progressDialog.dismiss();
                    //从第二个点开始
                    LatLng ll = new LatLng(bdLocation.getLatitude(),bdLocation.getLongitude());
                    //sdk回调gps位置的频率是1秒1个,位置点太近动态画在图上不是很明显,可以设置点之间距离大于为5米才添加到集合中,这里可以加入点抽稀算法
                    if (DistanceUtil.getDistance(lastPoint, ll) < 5) {
                        return;
                    }
    
    
                    points.add(ll);
                    //进行轨迹抽稀
    //                points_Sparsed = DouglasPeuckerUtil.DouglasPeucker(points,10);
    
    
                    lastPoint = ll;
    
                    //显示当前定位点,缩放地图
                    locateAndZoom(bdLocation,ll);
                    //清除上一次轨迹,避免重叠绘画
                    mMapView.getMap().clear();
                    //起始点的图层也会被清除重新绘画
                    BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(R.drawable.ic_start);
                    OverlayOptions oStart = new MarkerOptions()
                            .position(points_Sparsed.get(0))
                            .icon(bitmap);//地图标记覆盖物参数配置
                    mBaiduMap.addOverlay(oStart);
                    //绘制每一个点的标记点
                    BitmapDescriptor mPoint = BitmapDescriptorFactory.fromResource(R.drawable.ic_point);
                    for(LatLng point : points_Sparsed){
                        OverlayOptions posi = new MarkerOptions()
                            .position(point)
                            .icon(mPoint)
                            .draggable(true)
                            .flat(true)
                            .alpha(0.5f);//地图标记覆盖物参数配置
                        mBaiduMap.addOverlay(posi);
                    }
    //                OverlayOptions posi = new MarkerOptions()
    //                        .position(points_Sparsed.get(points_Sparsed.size()-1))
    //                        .icon(mPoint)
    //                        .draggable(true)
    //                        .flat(true)
    //                        .alpha(0.5f);//地图标记覆盖物参数配置
    //                markers.add(posi);
    
                    //将points集合中的点绘制轨迹线条图层,显示在地图上
                    //设置折线的属性
                    OverlayOptions mOverlayOptions = new PolylineOptions()
                            .width(13)
                            .color(0xAAFF0000)
                            .points(points_Sparsed);
    
                    //在地图上绘制折线
                    //mPloyline 折线对象
                    Overlay mPolyline = mBaiduMap.addOverlay(mOverlayOptions);
                    //添加所有的点
    //                for (OverlayOptions options : markers){
    //                    mBaiduMap.addOverlay(options);
    //                }
                }
            }
        }
    
        //首次定位很重要,选一个精度相对较高的起始点
        private LatLng getMostAccuracyLocation(final BDLocation location){
    
            if (location.getRadius()>25) {//gps位置精度大于25米的点直接弃用
                return null;
            }
    
            LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
    
            if (DistanceUtil.getDistance(lastPoint, ll ) > 5) {
                lastPoint = ll;
                points.clear();//有两点位置大于5,重新来过
                return null;
            }
            points.add(ll);
            lastPoint = ll;
            //有5个连续的点之间的距离小于5,认为gps已稳定,以最新的点为起始点
            if(points.size() >= 5){
                points.clear();
                return ll;
            }
            return null;
        }
        //显示当前定位点,缩放地图
        private void locateAndZoom(BDLocation location, LatLng ll){
            /**
             * 记录当前经纬度,当位置不变,手机转动,取得方向传感器的方向,
             给地图重新设置位置参数,在跟随模式下可使地图箭头随手机转动而转动
             */
            mCurrentLat = location.getLatitude();
            mCurrentLon = location.getLongitude();
            locData = new MyLocationData.Builder().accuracy(location.getRadius())//去掉精度圈
                    //此mCurrentDirection为自己获取到的手机传感器方向信息,顺时针0-360
                    .direction(location.getDirection()).latitude(location.getLatitude())
                    .longitude(location.getLongitude()).build();
            mBaiduMap.setMyLocationData(locData);//显示当前定位位置点
    
    //给地图设置缩放中心点,和缩放比例值
            builder = new MapStatus.Builder();
            builder.target(ll).zoom(mCurrentZoom);
            mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()));
        }
    
    }
    
    
  • 相关阅读:
    【MFC】在CHtmlView中在同一窗口显示新打开页面
    【MFC】CHtmlView::GetSource中文乱码的问题
    【Win32】对指定进程进行禁音
    【MFC】在CHtmlView中准确判断页面加载完成
    【MFC】CHtmlView或WebBrowser禁止脚本错误提示
    【MFC】CDialogBar中按钮不可用
    【转载记录】Accessing Device Drivers from C#
    【源代码R3】移植一份LARGE_INTEGER转时间的代码
    Square Root of Permutation
    MySQL创建视图命令
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13860127.html
Copyright © 2011-2022 走看看