百度地图上根据经纬度集合绘制行车轨迹

2023-05-16

以下是素材:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

最近项目中用到了根据一段线路的经纬度集合来在地图上播放该车辆的行驶轨迹的需求.下面我就讲一下我实现步骤:
效果图如下(因为制作gif图为了控制大小去掉了很多帧,不必在意这些细节,嘿嘿!!!):
在这里插入图片描述
1.首先在界面上展示百度地图(这不是废话么)如果不知道怎么展示请看我之前的博客.

2.初始化控件,把需要绘制在地图上的BitmapDescriptor准备好.也一个起点和终点的图标和灰色的线和绿色的线还有一辆小车.

3.调用百度地图的api把对应的图标绘制上去也就是addOverlay()这个方法.

4.然后就是循环不停的移动小车在地图上的位置了.

完成以上四步也就完成了轨迹播放的功能

初始化控件:

//初始化控件
        mMapView = findViewById(R.id.bmapView);
        BaiduMap mBaiduMap = mMapView.getMap();

处理数据:(这里由于每个人的数据源不同所以逻辑也不同,此处需要把自己的逻辑写进去)

//处理数据源,把assets中的文件数据转化成一个装有位置的集合
        List<Data> location = JsonReadUtil.fromJsonArray2(this, "test.json");
        latLngs = new ArrayList<>();
        LatLngBounds.Builder tempBounds = new LatLngBounds.Builder();
        for (int i = 0; i < location.size(); i++) {
            LatLng latLng = new LatLng(location.get(i).baidulat, location.get(i).baidulng);
            latLngs.add(latLng);
            tempBounds.include(latLng);
        }

注意:tempBounds.include(latLng);这个方法只是为了让地图上展示出我所有的经纬度而设定的,可根据自己的业务需要加入与否.

把需要绘制的图标设置好:

//五个需要绘制在地图上的图标
        BitmapDescriptor blueArrow = BitmapDescriptorFactory
                .fromResource(R.mipmap.icon_road_blue_arrow);
        BitmapDescriptor grayArrow = BitmapDescriptorFactory
                .fromResource(R.mipmap.icon_road_gray_arrow);
        BitmapDescriptor che = BitmapDescriptorFactory
                .fromResource(R.mipmap.che);
        BitmapDescriptor qi = BitmapDescriptorFactory
                .fromResource(R.mipmap.qi);
        BitmapDescriptor zhong = BitmapDescriptorFactory
                .fromResource(R.mipmap.zhong);

调用addOverlay()方法把图标绘制上去:

//控制线条的宽度样式等(画线)
        PolylineOptions ooPolyline = new PolylineOptions().customTexture(blueArrow).width(20).dottedLine(true).points(latLngs);
        PolylineOptions ooPolyline2 = new PolylineOptions().customTexture(grayArrow).width(20).dottedLine(true).points(latLngs);
        //在地图上批量添加(把灰线绘制入百度地图中)
        mBaiduMap.addOverlay(ooPolyline);
        //在地图上批量添加(把蓝线绘制入百度地图中)
        mPolyline2 = (Polyline) mBaiduMap.addOverlay(ooPolyline2);

        //拿到集合的第一个位置
        LatLng pointQi = new LatLng(location.get(0).baidulat, location.get(0).baidulng);
        //画起点的图标(也就是集合的第一个位置就是起点)
        OverlayOptions optionQi = new MarkerOptions().position(pointQi).icon(qi);
        //拿到集合最后一个位置
        LatLng pointZhong = new LatLng(location.get(location.size() - 1).baidulat, location.get(location.size() - 1).baidulng);
        //画终点的图标(也就是集合的最后一个位置就是终点)
        OverlayOptions optionZhong = new MarkerOptions().position(pointZhong).icon(zhong);
        //拿到集合的第一个位置
        LatLng pointChe = new LatLng(location.get(0).baidulat, location.get(0).baidulng);
        //画车辆的图标(因为车辆是从第一个位置开始行驶的,所以车辆的初始位置是第一个)
        MarkerOptions markerOptions = new MarkerOptions().position(pointChe).icon(che);

        //创建OverlayOptions的集合(把起点终点和车辆绘制在地图上)
        List<OverlayOptions> options = new ArrayList<>();
        options.add(optionQi);
        options.add(optionZhong);
        mMoveMarker = (Marker) mBaiduMap.addOverlay(markerOptions);
        //(绘制在地图上)
        mBaiduMap.addOverlays(options);

        LatLngBounds mBaiduLatLngBounds = tempBounds.build();
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLngBounds(mBaiduLatLngBounds));

循环移动:

/**
     * 循环进行移动逻辑
     */
    public void moveLooper() {
        //为了不阻塞ui线程所以开启子线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //死循环
                while (true) {
                    for (int i = 0; i < latLngs.size() - 1; i++) {
                        final LatLng startPoint = latLngs.get(i);
                        final LatLng endPoint = latLngs.get(i + 1);
                        mMoveMarker
                                .setPosition(startPoint);

                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                // refresh marker's rotate
                                if (mMapView == null) {
                                    return;
                                }
                                mMoveMarker.setRotate((float) getAngle(startPoint,
                                        endPoint));
                            }
                        });
                        double slope = getSlope(startPoint, endPoint);
                        // 是不是正向的标示
                        boolean isReverse = (startPoint.latitude > endPoint.latitude);

                        double intercept = getInterception(slope, startPoint);

                        double xMoveDistance = isReverse ? getXMoveDistance(slope) :
                                -1 * getXMoveDistance(slope);


                        for (double j = startPoint.latitude; !((j > endPoint.latitude) ^ isReverse);
                             j = j - xMoveDistance) {
                            LatLng latLng;
                            if (slope == Double.MAX_VALUE) {
                                latLng = new LatLng(j, startPoint.longitude);
                            } else {
                                latLng = new LatLng(j, (j - intercept) / slope);
                            }
                            final LatLng finalLatLng = latLng;
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (mMapView == null) {
                                        return;
                                    }
                                    mMoveMarker.setPosition(finalLatLng);
                                    latLngs2.add(startPoint);
                                    latLngs2.add(finalLatLng);
                                    mPolyline2.setPoints(latLngs2);
                                }
                            });
                            try {
                                Thread.sleep(TIME_INTERVAL);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }
            }
        }).start();
    }

关于计算的方法:

/**
     * 根据两点算取图标转的角度
     */
    private double getAngle(LatLng fromPoint, LatLng toPoint) {
        double slope = getSlope(fromPoint, toPoint);
        if (slope == Double.MAX_VALUE) {
            if (toPoint.latitude > fromPoint.latitude) {
                return 0;
            } else {
                return 180;
            }
        }
        float deltAngle = 0;
        if ((toPoint.latitude - fromPoint.latitude) * slope < 0) {
            deltAngle = 180;
        }
        double radio = Math.atan(slope);
        return 180 * (radio / Math.PI) + deltAngle - 90;
    }

    /**
     * 根据点和斜率算取截距
     */
    private double getInterception(double slope, LatLng point) {

        return point.latitude - slope * point.longitude;
    }

    /**
     * 算斜率
     */
    private double getSlope(LatLng fromPoint, LatLng toPoint) {
        if (toPoint.longitude == fromPoint.longitude) {
            return Double.MAX_VALUE;
        }
        return ((toPoint.latitude - fromPoint.latitude) / (toPoint.longitude - fromPoint.longitude));

    }

贴上我全部的代码:(具体的注释已经写的很清楚了)

private MapView mMapView;
    private Polyline mPolyline2;
    private Handler mHandler;
    private ArrayList<LatLng> latLngs;
    private Marker mMoveMarker;
    // 通过设置间隔时间和距离可以控制速度和图标移动的距离
    private static final int TIME_INTERVAL = 80;
    private static final double DISTANCE = 0.00250;
    private ArrayList<LatLng> latLngs2 = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控件
        mMapView = findViewById(R.id.bmapView);
        BaiduMap mBaiduMap = mMapView.getMap();


        //处理数据源,把assets中的文件数据转化成一个装有位置的集合
        List<Data> location = JsonReadUtil.fromJsonArray2(this, "test.json");
        latLngs = new ArrayList<>();
        LatLngBounds.Builder tempBounds = new LatLngBounds.Builder();
        for (int i = 0; i < location.size(); i++) {
            LatLng latLng = new LatLng(location.get(i).baidulat, location.get(i).baidulng);
            latLngs.add(latLng);
            tempBounds.include(latLng);
        }

        mHandler = new Handler(Looper.getMainLooper());

        //五个需要绘制在地图上的图标
        BitmapDescriptor blueArrow = BitmapDescriptorFactory
                .fromResource(R.mipmap.icon_road_blue_arrow);
        BitmapDescriptor grayArrow = BitmapDescriptorFactory
                .fromResource(R.mipmap.icon_road_gray_arrow);
        BitmapDescriptor che = BitmapDescriptorFactory
                .fromResource(R.mipmap.che);
        BitmapDescriptor qi = BitmapDescriptorFactory
                .fromResource(R.mipmap.qi);
        BitmapDescriptor zhong = BitmapDescriptorFactory
                .fromResource(R.mipmap.zhong);

        //控制线条的宽度样式等(画线)
        PolylineOptions ooPolyline = new PolylineOptions().customTexture(blueArrow).width(20).dottedLine(true).points(latLngs);
        PolylineOptions ooPolyline2 = new PolylineOptions().customTexture(grayArrow).width(20).dottedLine(true).points(latLngs);
        //在地图上批量添加(把灰线绘制入百度地图中)
        mBaiduMap.addOverlay(ooPolyline);
        //在地图上批量添加(把蓝线绘制入百度地图中)
        mPolyline2 = (Polyline) mBaiduMap.addOverlay(ooPolyline2);

        //拿到集合的第一个位置
        LatLng pointQi = new LatLng(location.get(0).baidulat, location.get(0).baidulng);
        //画起点的图标(也就是集合的第一个位置就是起点)
        OverlayOptions optionQi = new MarkerOptions().position(pointQi).icon(qi);
        //拿到集合最后一个位置
        LatLng pointZhong = new LatLng(location.get(location.size() - 1).baidulat, location.get(location.size() - 1).baidulng);
        //画终点的图标(也就是集合的最后一个位置就是终点)
        OverlayOptions optionZhong = new MarkerOptions().position(pointZhong).icon(zhong);
        //拿到集合的第一个位置
        LatLng pointChe = new LatLng(location.get(0).baidulat, location.get(0).baidulng);
        //画车辆的图标(因为车辆是从第一个位置开始行驶的,所以车辆的初始位置是第一个)
        MarkerOptions markerOptions = new MarkerOptions().position(pointChe).icon(che);

        //创建OverlayOptions的集合(把起点终点和车辆绘制在地图上)
        List<OverlayOptions> options = new ArrayList<>();
        options.add(optionQi);
        options.add(optionZhong);
        mMoveMarker = (Marker) mBaiduMap.addOverlay(markerOptions);
        //(绘制在地图上)
        mBaiduMap.addOverlays(options);

        LatLngBounds mBaiduLatLngBounds = tempBounds.build();
        mBaiduMap.animateMapStatus(MapStatusUpdateFactory.newLatLngBounds(mBaiduLatLngBounds));
        //循环移动车辆位置
        moveLooper();
    }

    /**
     * 计算x方向每次移动的距离
     */
    private double getXMoveDistance(double slope) {
        if (slope == Double.MAX_VALUE) {
            return DISTANCE;
        }
        return Math.abs((DISTANCE * slope) / Math.sqrt(1 + slope * slope));
    }

    /**
     * 循环进行移动逻辑
     */
    public void moveLooper() {
        //为了不阻塞ui线程所以开启子线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //死循环
                while (true) {
                    for (int i = 0; i < latLngs.size() - 1; i++) {
                        final LatLng startPoint = latLngs.get(i);
                        final LatLng endPoint = latLngs.get(i + 1);
                        mMoveMarker
                                .setPosition(startPoint);

                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                // refresh marker's rotate
                                if (mMapView == null) {
                                    return;
                                }
                                mMoveMarker.setRotate((float) getAngle(startPoint,
                                        endPoint));
                            }
                        });
                        double slope = getSlope(startPoint, endPoint);
                        // 是不是正向的标示
                        boolean isReverse = (startPoint.latitude > endPoint.latitude);

                        double intercept = getInterception(slope, startPoint);

                        double xMoveDistance = isReverse ? getXMoveDistance(slope) :
                                -1 * getXMoveDistance(slope);


                        for (double j = startPoint.latitude; !((j > endPoint.latitude) ^ isReverse);
                             j = j - xMoveDistance) {
                            LatLng latLng;
                            if (slope == Double.MAX_VALUE) {
                                latLng = new LatLng(j, startPoint.longitude);
                            } else {
                                latLng = new LatLng(j, (j - intercept) / slope);
                            }
                            final LatLng finalLatLng = latLng;
                            mHandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (mMapView == null) {
                                        return;
                                    }
                                    mMoveMarker.setPosition(finalLatLng);
                                    latLngs2.add(startPoint);
                                    latLngs2.add(finalLatLng);
                                    mPolyline2.setPoints(latLngs2);
                                }
                            });
                            try {
                                Thread.sleep(TIME_INTERVAL);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }
            }
        }).start();
    }

    /**
     * 根据两点算取图标转的角度
     */
    private double getAngle(LatLng fromPoint, LatLng toPoint) {
        double slope = getSlope(fromPoint, toPoint);
        if (slope == Double.MAX_VALUE) {
            if (toPoint.latitude > fromPoint.latitude) {
                return 0;
            } else {
                return 180;
            }
        }
        float deltAngle = 0;
        if ((toPoint.latitude - fromPoint.latitude) * slope < 0) {
            deltAngle = 180;
        }
        double radio = Math.atan(slope);
        return 180 * (radio / Math.PI) + deltAngle - 90;
    }

    /**
     * 根据点和斜率算取截距
     */
    private double getInterception(double slope, LatLng point) {

        return point.latitude - slope * point.longitude;
    }

    /**
     * 算斜率
     */
    private double getSlope(LatLng fromPoint, LatLng toPoint) {
        if (toPoint.longitude == fromPoint.longitude) {
            return Double.MAX_VALUE;
        }
        return ((toPoint.latitude - fromPoint.latitude) / (toPoint.longitude - fromPoint.longitude));

    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

百度地图上根据经纬度集合绘制行车轨迹 的相关文章

随机推荐

  • Activiti学习笔记一 工作流基本概念

    最近刚接触流程引擎这一概念 xff0c 对Activiti进行学习 xff0c 感觉正在入门中 xff0c 整理下自己的学习笔记把 xff01 1 xff1a 工作流的概念 工作流 Workflow xff0c 就是 业务过程的部分或整体在
  • Activiti学习笔记六 流程实例 任务 执行对象控制流程执行

    上一篇我们看了流程定义 xff0c 我们接下来看一下流程实例 xff0c 任务 xff0c 和执行对象 流程实例 任务的执行 1 流程图 2 部署流程定义 private final ProcessEngine processEngine
  • datetimepicker 控件验证问题

    34 baseStudents activistTime 34 trigger 39 blur 39 validators notEmpty message 39 确定积极分子时间不能为空 39 span class hljs tag lt
  • eclipse中SVN分支合并到主干

    在项目开发中 xff0c 需要添加一些新的功能 xff0c 但是又不想影响到其他开发人员的项目进度 xff0c 所以决定使用SVN分支进行开发 xff0c 分支开发完毕后再合并到主干 本文介绍如何在eclipse中合并分支到主干 要想将分支
  • 阿里云服务器

    一年多之前 xff0c 也就11年5月份的样子 xff0c 阿里云云服务器产品线终于上线了 但那时候 xff0c 国内完全没有能称得上云服务器的 xff0c 很多小公司就是搞个VPS就叫云服务器了 以至于阿里云云服务器刚出来的时候 xff0
  • mac 下 使用 iterm2 配置及快键键使用

    mac 下 使用 iterm2 配置及快键键使用 标签 xff08 空格分隔 xff09 xff1a mac 之前介绍过一篇关于mac 下使用和配置 iterm2的blog 今天这篇稍微详细一点介绍 并且搭配 zsh zsh 会单独开一篇博
  • Java实现快速排序

    一 原理 快速排序算法通过多次比较和交换来实现排序 xff0c 其排序流程如下 xff1a 1 首先设定一个分界值 xff0c 通过该分界值将数组分成左右两部分 2 将大于或等于分界值的数据集中到数组右边 xff0c 小于分界值的数据集中到
  • C#,生信软件实践(03)——DNA数据库GenBank格式详解及转为FASTA序列格式的源代码

    1 GenBank 1 1 NCBI 美国国家生物技术信息中心 xff08 美国国立生物技术信息中心 xff09 NCBI xff08 美国国立生物技术信息中心 xff09 是在NIH的国立医学图书馆 xff08 NLM xff09 的一个
  • 【坑】zsh和oh-my-zsh卸载后导致无法登陆

    apt get remove zsh 然后断开终端 xff0c 就再也连不上了 xff0c 崩溃啊 xff01 以下登陆为www用户登陆 各种找 xff0c 到这里 https www cnblogs com EasonJim p 7863
  • 获取最近使用应用列表

    获取最近使用的应用列表需要使用到UsageStatsManager类 xff0c 还需要申请允许防御应用使用情况的权限 private void getPackagesInfo UsageStatsManager manager 61 Us
  • 使用MediaProjectionManager进行截屏

    最近项目中有用到远程截屏并上传截屏文件的需求 一开始使用的是以下方法进行截屏 xff1a private void screenshot 获取屏幕 View dView 61 getWindow getDecorView dView set
  • 安卓TV开发遇到的那些坑

    最近公司需要开发一个TV的luancher xff0c 就是那种纯物理按键的遥控 xff0c 没有触摸屏 xff0c 现在说说我踩得那些坑 xff08 其实布局和代码逻辑和正常的安卓应用差不多 xff09 1 焦点 焦点 焦点 xff0c
  • 安卓TV列表刷新时焦点自动变成第一个

    最近在开发安卓TV项目 xff0c 列表调用notifyDataSetChanged xff08 xff09 方法刷新数据时 xff0c 焦点自动就变成第一个子item去了 xff0c 查了半天发现用notifyItemRangeChang
  • 安卓蓝牙BLE设备通讯发送和接受超过20个字节的问题

    最近做的项目是手机端和BLE设备通讯 xff0c 而BLE设备又做了限制一次包只能传递20个字节的数据 xff0c 多了就得分包发送 xff0c 在这里记录一下如何解决这个问题 xff08 PS xff1a 之前链接什么的回调什么的 就不过
  • 获取最近运行应用方法和杀进程的方法

    最近公司的项目有个需求就是获取最近手机正在运行的进程 xff0c 以及杀掉进程 就是类似于安卓手机中的长按home键的效果 先说说获取最近手机正在运行的进程方法 xff1a 直接上代码 xff0c 代码中有注释 xff1a appbeans
  • 把自己的应用程序push至system/app下,把自己的app改成系统级别的app

    想把一个应用程序放入到系统文件夹下的话 xff0c 手机必须的root的情况下才能push进去 下面我就说说步骤吧 xff1a 1 先把手机用USB和电脑连接 2 如果电脑配置了adb的环境的话直接cmd xff0c 未配置环境的话找到sd
  • ConcurrentModificationException异常出现原因以及解决方法

    今天在开发过程中遇到一个异常叫ConcurrentModificationException xff0c 这个异常用我的白话翻译是叫同时修改异常 这个异常是怎么出现的呢 xff0c 先看看已下的代码 xff1a span class hlj
  • retrofit中使用body标签传RequestBody

    现在的Android开发者基本上都用过retrofit这个第三方网络请求库吧 xff01 xff01 xff01 网络请求中有get post delete和put等等请求方式 现在我们需要用到post请求 xff1a span class
  • SpringBoot配置拦截器拦截器使用

    拦截器介绍 Java中的拦截器是动态拦截 action 调用的对象 xff0c 然后提供了可以在 action 执行前后增加一些操作 xff0c 也可以在 action执行前停止操作 xff0c 功能与过滤器类似 xff0c 但是标准和实现
  • 百度地图上根据经纬度集合绘制行车轨迹

    以下是素材 最近项目中用到了根据一段线路的经纬度集合来在地图上播放该车辆的行驶轨迹的需求 下面我就讲一下我实现步骤 效果图如下 因为制作gif图为了控制大小去掉了很多帧 不必在意这些细节 嘿嘿 1 首先在界面上展示百度地图 这不是废话么 如