-
java 轨迹平滑算法_地图坐标轨迹平滑和纠偏
2021-03-09 21:07:13轨迹平滑和纠偏纠偏通过gps获取坐标点时 因为gps信号不稳定等原因 出现坐标点异常 不符合实际 进行异常点的处理 来对轨迹纠正轨迹偏移不正常取得轨迹坐标集合 对此段轨迹设置起点和终点 取得相邻两坐标点 计算出两点...轨迹平滑和纠偏
纠偏
通过gps获取坐标点时 因为gps信号不稳定等原因 出现坐标点异常 不符合实际 进行异常点的处理 来对轨迹纠正
轨迹偏移不正常
取得轨迹坐标集合 对此段轨迹设置起点和终点 取得相邻两坐标点 计算出两点之间距离 对比获取坐标点的时间 判断坐标时速异常 对坐标点移除处理
代码逻辑
异常点去除之后轨迹
轨迹平滑处理
实现思路方法
1.百度地图鹰眼服务:
源码主要实现思路:计算相邻坐标点之间距离 通过时间判断速度 挑出 异常点 绑定道路的实现方式
2.数据库坐标去重过滤:
高斯滤波:.
百度鹰眼服务
文档地址:http://lbsyun.baidu.com/index.php?title=yingyan/api/v3/trackupload
上传轨迹 —轨迹处理—返回轨迹
请求方式 http://yingyan.baidu.com/api/v3/track/addpoint //POST请求
参数
核心参数
ak 用户授权标识
Service_id 鹰眼服务标识
entity_name 轨迹所属实例
Longitude 经度
Latitude 纬度
loc_time 获取坐标点时间
coord_type_input 坐标类型
wgs84:GPS 坐标
gcj02:国测局加密坐标
bd09ll:百度经纬度坐标
返回值参数
多轨迹上传
可上传多个实例的多个轨迹 核心方法 addpoins
http://yingyan.baidu.com/api/v3/track/addpoints //POST请求
所需参数如下
Point_list 为多个实例和轨迹的集合格式如下 返回值如下
这是entity实例 可单个上传或批量
这是属于entity的轨迹addpionts 可批量上传 单独上传 进行轨迹处理
可有去噪 抽稀 绑路 终端补偿等 在传递参数时设置 返回纠正后集合
纠正之后
数据库坐标去重过滤
以下方案摘取:https://www.jianshu.com/p/1c71d10e18bf
将取到的若干坐标点存入到数据库 核心字段 id 经纬度 时间
将数据库坐标点去重
数据平滑采用高斯滤波进行平滑处理
将处理后的坐标点铺到地图上
坐标匹配到道路上去,但是由于精度不是那么可靠,切在转弯处的数据匹配也是明显的错误,但是目前没找到好的解决方案
总结:
无论纠偏、异常点处理、轨迹平滑 其根本都是对坐标点的处理 核心参数是经纬度以及经纬度对应的时间 进行处理 在坐标点做够多的情况下 gps不稳定获取的坐标点不够精确导致的问题
-
Android车辆轨迹平滑移动
2018-10-19 16:11:08基于高德地图3D API做的点平滑移动效果,Android车辆轨迹平滑移动【旧版本】 -
连续轨迹平滑过渡控制算法研究
2021-01-29 01:20:04为了解决传统的点位控制算法在加工复杂轨迹时速度频繁变化造成的机床抖动、加工效率低等问题,提出连续轨迹平滑过渡算法。文中首先指出插补离散化导致连续轨迹需要跨段过渡,然后提出两种连续轨迹单周期过渡方案并... -
基于轨迹平滑的室内移动目标定位算法
2021-03-18 10:49:48基于轨迹平滑的室内移动目标定位算法 -
一种轨迹平滑方法
2015-03-18 17:24:46一种很好的轨迹平滑方法,很有创新性和实用性。 -
地图坐标轨迹平滑和纠偏
2020-06-01 15:57:18轨迹平滑和纠偏 纠偏 通过gps获取坐标点时 因为gps信号不稳定等原因 出现坐标点异常 不符合实际 进行异常点的处理 来对轨迹纠正 轨迹偏移不正常 取得轨迹坐标集合 对此段轨迹设置起点和终点 取得相邻两坐标点 计算...轨迹平滑和纠偏
纠偏
通过gps获取坐标点时 因为gps信号不稳定等原因 出现坐标点异常 不符合实际 进行异常点的处理 来对轨迹纠正
轨迹偏移不正常取得轨迹坐标集合 对此段轨迹设置起点和终点 取得相邻两坐标点 计算出两点之间距离 对比获取坐标点的时间 判断坐标时速异常 对坐标点移除处理
代码逻辑:
异常点去除之后轨迹
轨迹平滑处理
实现思路方法
1.百度地图鹰眼服务:
源码主要实现思路:计算相邻坐标点之间距离 通过时间判断速度 挑出 异常点 绑定道路的实现方式
2.数据库坐标去重过滤:百度鹰眼服务
文档地址:http://lbsyun.baidu.com/index.php?title=yingyan/api/v3/trackupload
上传轨迹 —轨迹处理—返回轨迹
请求方式 http://yingyan.baidu.com/api/v3/track/addpoint //POST请求参数
核心参数
ak 用户授权标识
Service_id 鹰眼服务标识
entity_name 轨迹所属实例
Longitude 经度
Latitude 纬度
loc_time 获取坐标点时间
coord_type_input 坐标类型
wgs84:GPS 坐标
gcj02:国测局加密坐标
bd09ll:百度经纬度坐标请求参数:
返回值参数
多轨迹上传
可上传多个实例的多个轨迹 核心方法 addpoins
http://yingyan.baidu.com/api/v3/track/addpoints //POST请求所需参数如下:
Point_list 为多个实例和轨迹的集合格式如下 返回值如下
这是entity实例
可单个上传或批量
这是属于entity的轨迹addpionts 可批量上传 单独上传 进行轨迹处理
可有去噪 抽稀 绑路 终端补偿等 在传递参数时设置 返回纠正后集合纠正之后
数据库坐标去重过滤
以下方案摘取:https://www.jianshu.com/p/1c71d10e18bf将取到的若干坐标点存入到数据库 核心字段 id 经纬度 时间
将数据库坐标点去重
数据平滑采用高斯滤波进行平滑处理
将处理后的坐标点铺到地图上
坐标匹配到道路上去,但是由于精度不是那么可靠,切在转弯处的数据匹配也是明显的错误,但是目前没找到好的解决方案总结:
无论纠偏、异常点处理、轨迹平滑 其根本都是对坐标点的处理 核心参数是经纬度以及经纬度对应的时间 进行处理 在坐标点做够多的情况下 gps不稳定获取的坐标点不够精确导致的问题小白编写 不喜勿喷 欢迎纠错
博文地址:https://me.csdn.net/YaoChiZaoFan -
地图轨迹平滑算法
2016-08-04 00:21:34地图轨迹平滑算法,Savitzky-Golay 滤波器地图轨迹平滑算法
引子:
之前看到网上有大神写过一个demo:
http://blog.csdn.net/zhoumushui/article/details/41751259
但是提供的代码不全,一直没有明白这个算法是怎么做的:算法说明:
后来一次偶然的机会,看到这篇文章(注意,这篇文章里的代码,部分算法的参数是错的):
http://blog.csdn.net/liyuanbhu/article/details/11119081
其中的5点平滑代码恰恰和之前描述的一样,原来之前的文章只给出了边缘4个点(最前面2个点、最后面2个点),恰恰漏掉了最关键的中间所有点、虽然只是简单的5点平均这个算法是Savitzky-Golay 滤波器的“5点1阶”算法。那么,怎么推导出“n点k阶”的系数呢?笔者没有时间去仔细研究算法本身,只想找到最快的方法解决问题,最后发现可以通过MatLab直接的得到这些参数,比如:
这个矩阵前2行对应前两个点的系数,后2行对应后两个点的系数,中间行对应中间所有点的系数。结论:这样就完成了,用MatLab 根据需要得到矩阵,然后就可以编程了!
-
高德地图轨迹平滑移动改进demo
2016-11-24 17:05:32对高德地图轨迹平滑移动的官方demo做了一点改进,易于大家理解。 -
LBS轨迹平滑播放示例
2013-01-27 17:59:14LBS轨迹平滑播放示例,还有用到的TimeLineLite.min.js -
一种基于小波降噪的GNSS轨迹平滑算法
2020-10-18 16:43:06算法对基于伪码测距和载波多普勒平滑伪距的解算结果进行差分,并根据差分值的频谱特征,选择合适的尺度进行小波降噪处理后,与基于载波多普勒平滑伪距的解算结果求和得到轨迹平滑结果。仿真结果表明,该算法在载体... -
Arcgis实现单目标多目标地图轨迹平滑移动.zip
2019-10-16 11:48:23利用Arcgis的API实现地图目标轨迹平滑移动。多目标示例:实现多个目标同时在地图上沿轨迹坐标点平滑移动,支持设置移动速度。单个目标示例有暂停、继续等功能代码。代码示例仅供参考。 -
减振数控加工轨迹平滑和进给速度调度的建模与仿真
2021-03-09 10:08:15在最近的研究中,开发了G2 / G3(曲率连续/平滑)轨迹平滑和加加速度限制/连续进给率调度方案。 尽管如此,仍然存在一些无法同时满足的要求,包括有限的弦误差,G01点插值,解析曲率极值,实时性能,运动时间最优性... -
【自动驾驶】运动规划丨轨迹规划丨基于改进Dijkstra算法的轨迹平滑方法.zip
2021-04-11 21:07:18dijkstra算法轨迹平滑,传感器融合标定算法,另外还包含了自动驾驶学习资料 涵盖感知,规划和控制,ADAS,传感器; 1. apollo相关的技术教程和文档; 2.adas(高级辅助驾驶)算法设计(例如AEB,ACC,LKA等) 3.自动... -
Android车辆运动轨迹平滑移动(高仿滴滴打车)最佳实践
2019-07-13 20:50:54关于车辆运动的相关文章一共写过两篇,一篇为Android车辆运动轨迹大数据采集最佳...一直打算写一篇车辆运动轨迹平滑移动的文章,年后由于工作项目太忙也就没时间写,工作的事情忙完了,紧接着就是忙自己的另外两个开...版权声明:本文来自门心叼龙的博客,属于原创内容,转载请注明出处:https://menxindiaolong.blog.csdn.net/article/details/95789128
github源码下载地址:https://github.com/geduo83/android-amap-movecar
关于车辆运动的相关文章一共写过两篇,一篇为Android车辆运动轨迹大数据采集最佳实践,另外一篇是Android车辆运动轨迹数据采集服务保活的探索与发现,
一直打算写一篇车辆运动轨迹平滑移动的文章,年后由于工作项目太忙也就没时间写,工作的事情忙完了,紧接着就是忙自己的另外两个开源项目,一个是Android客户端框架FlyTour
、和另外一个SpringCloud微服务框架FlyCloud,上个周终于告一段落。数据也能采集了,而且采集服务保活也做了,有效的避免了数据采集服务在后台被系统杀死的可能,接着就需要把采集到的数据在移动设备上实时的展示出来,这两天我也特意在网上搜索了一下,关于Android车辆运动轨迹平滑移动的文章,还真没有,大部分都是提问的多,问怎么实现的?都是一些只言片语很零碎的一些回答,在实战项目当中没有太大的实用价值。
关于车辆运动,在我们在日常生活中见到最多的就是滴滴打车,想必这款app大家都使用过,当你在app的叫车页面,输入完毕你的目的地,点击叫车,如果有司机接单了,你就清楚的看到车辆会平滑的移动到你所在的位置去接你。今天我就带领大家一步步的实现一个车辆平滑移动的功能。
这个功能是基于高德地图开发的,因此我特意去高德官网查阅了一下,高德的确提供了官方轨迹移动api,我们暂且不用官方API.先用自己的方法去实现一个最简单的功能
我们先来一睹为快:
单次轨迹回放
已知有一段轨迹数据,点击回放按钮,小车沿着路线自动的往前运动,播放完毕也就结束了
public class MoveSingleThread extends Thread{ private List<LatLng> mLatLngList; private Marker mCarMarker; public MoveSingleThread(List<LatLng> latLngs, Marker marker) { super(); mLatLngList = latLngs; mCarMarker = marker; } @Override public void run() { super.run(); } public void moveTrack(){ // 第一个for循环用来计算走了多少部 int step = 0; for (int i = 0; i < mLatLngList.size() - 1; i++) { LatLng startPoint = mLatLngList.get(i); LatLng endPoint = mLatLngList.get(i + 1); double slope = getSlope(startPoint, endPoint); // 是不是正向的标示(向上设为正向) boolean isReverse = (startPoint.latitude > endPoint.latitude); double xMoveDistance = isReverse ? getXMoveDistance(slope) : -1 * getXMoveDistance(slope); // 应该对经纬度同时处理 for (double j = startPoint.latitude; !((j >= endPoint.latitude) ^ isReverse); j = j - xMoveDistance) { step++; } } // 通过距离,计算轨迹动画时间间隔 double mTimeInterval = 0;// 轨迹回放时间戳 if (!TextUtils.isEmpty(mDistance)) { float totalDistance = Float.parseFloat(mDistance) * 1000; if (totalDistance <= 500) { mTimeInterval = 1000.0 / step; } else if (totalDistance > 500 && totalDistance <= 7500) { mTimeInterval = 2.0 * totalDistance / step; } else { mTimeInterval = 15000.0 / step; } } // while (true) { for (int i = 0; i < mLatLngList.size() - 1; i++) { if (stopFlag) { stopFlag = false; break; } mIsCarMoveing = true; LatLng startPoint = mLatLngList.get(i); LatLng endPoint = mLatLngList.get(i + 1); mCarMarker.setPosition(startPoint); mCarMarker.setRotateAngle((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); // 应该对经纬度同时处理 double mSleep = 0; for (double j = startPoint.latitude; !((j >= endPoint.latitude) ^ isReverse); j = j - xMoveDistance) { LatLng latLng = null; if (slope != Double.MAX_VALUE) { latLng = new LatLng(j, (j - intercept) / slope); // latLng = new LatLng(j, k); } else { latLng = new LatLng(j, startPoint.longitude); } mCarMarker.setPosition(latLng); // 如果间隔时间小于1毫秒,则略过当前休眠,累加直到休眠时间到1毫秒:会损失精度 if (mTimeInterval < 1) { mSleep += mTimeInterval; if (mSleep >= 1) { SystemClock.sleep((long) mSleep); mSleep = 0; } } else SystemClock.sleep((long) mTimeInterval); } } } }
实时轨迹数据排队问题
如果要显示实时轨迹怎么办 ,上面的代码就有问题了,Thread.start()方法调用后,就会立马执行他的run方法,run方法执行完毕,线程也就结束了,也是说上面的代码只能跑一次轨迹数据,如果每间隔五秒从后台取一次轨迹数据,就需要一数据队列来存储这些数据,每跑完一次数据,就从数据队列里面去取,如果有就取来接着跑,如果没有就处于等待状态。 我们创建异步消息处理线程,这一问题就可以迎刃而解,来数据了我们就可以通过handler把数据post给我们的子线程,Handler自带数据队列,它处于排队状态,如果有数据了就开始跑轨迹,如果没有数据就处于等待状态,直到有数据的到来,如果对异步消息处理线程不熟悉,请查看我的另外一篇文章Android实战开发Handler机制深度解析https://menxindiaolong.blog.csdn.net/article/details/86560330
一个标准的异步消息处理线程应该怎么写?
方法1:class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); } }
方法2:
// Step 1: 创建并启动HandlerThread线程,内部包含Looper HandlerThread handlerThread = new HandlerThread("gityuan.com"); handlerThread.start(); // Step 2: 创建Handler Handler handler = new Handler(handlerThread.getLooper()) { public void handleMessage(Message msg) { // process incoming messages here } }; // Step 3: 发送消息 handler.post(new Runnable() { @Override public void run() { System.out.println("thread id="+Thread.currentThread().getId()); } });
上面就是Android系统中异步消息处理线程的通用写法
运动轨迹的暂停、继续问题
由于运动轨迹是在子线程里面完成的,我们自然而然会想到线程的等待、唤醒,也就是wait、notify的问题了
因此我们在运动过程加上就如下代码就可以了if (pause) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }
怎么让他恢复运动呢?notify一下即可
public void reStartMove() { synchronized (lock) { pause = false; lock.notify(); } }
完整的代码如下:
/** * Description: <MoveCarCustomThread><br> * Author: mxdl<br> * Date: 2019/7/10<br> * Version: V1.0.0<br> * Update: <br> */ public class MoveCarCustomThread extends Thread { public static final String TAG = MoveCarCustomThread.class.getSimpleName(); private Handler moveCarHandler;//发送数据的异步消息处理器 private Object lock = new Object();//线程锁 private boolean moveing = false;//是否线程正在移动 private boolean pause = false;//暂停状态,为true则暂停 private boolean stop = false;//停止状态,为true则停止移动 private WeakReference<MainActivity> mActivityWeakReference;//防止内存Activity导致的内容泄漏 private MOVE_STATE currMoveState = MOVE_STATE.START_STATUS; public void setCurrMoveState(MOVE_STATE currMoveState) { this.currMoveState = currMoveState; } public MOVE_STATE getCurrMoveState() { return currMoveState; } public MoveCarCustomThread(MainActivity activity) { mActivityWeakReference = new WeakReference<>(activity); } //暂停移动 public void pauseMove() { pause = true; } //设置暂停之后,再次移动调用它 public void reStartMove() { synchronized (lock) { pause = false; lock.notify(); } } public void stopMove() { stop = true; if(moveCarHandler != null){ moveCarHandler.removeCallbacksAndMessages(null); } if(mActivityWeakReference.get() != null){ mActivityWeakReference.get().mLatLngList.clear(); mActivityWeakReference.get().mMainHandler.removeCallbacksAndMessages(null); } } public Handler getMoveCarHandler() { return moveCarHandler; } public boolean isMoveing() { return moveing; } @Override public void run() { super.run(); //设置该线程为loop线程 Looper.prepare(); moveCarHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); //通过锁保证发过来的数据同步入列 synchronized (lock) { if (msg.obj != null && msg.obj instanceof List) { List<LatLng> latLngList = (List<LatLng>) msg.obj; moveCoarseTrack(latLngList); } } } }; //启动loop线程 Looper.loop(); } private void moveCoarseTrack(List<LatLng> latLngList) { if (latLngList == null || latLngList.size() == 0 || latLngList.size() == 1) { return; } Log.v(TAG, "moveCoarseTrack start........................................................."); long startTime = System.currentTimeMillis(); Log.v(TAG, "startTime:" + startTime); int step = TrackMoveUtil.getStep(latLngList);// 通过距离,计算轨迹动画运动步数 Log.v(TAG, "move step:" + step); float distance = TrackMoveUtil.getDistance(latLngList); Log.v(TAG, "move distance:" + distance); double mTimeInterval = TrackMoveUtil.getMoveTime(distance, step);// 通过距离,计算轨迹动画时间间隔 mTimeInterval = 10;// 每走一步停止10毫秒 Log.v(TAG, "move mTimeInterval:" + mTimeInterval); moveing = true; for (int i = 0; i < latLngList.size() - 1; i++) { // 暂停状态,线程停止了 if (pause) { movePause(); } if (stop) { break; } moveing = true; LatLng startLatLng = latLngList.get(i); LatLng endLatLng = latLngList.get(i + 1); MainActivity mainActivity = mActivityWeakReference.get(); moveCar(startLatLng, endLatLng, mainActivity); moveLine(startLatLng, mainActivity); moveCamera(startLatLng, mainActivity); double slope = TrackMoveUtil.getSlope(startLatLng, endLatLng);// 计算两点间的斜率 double intercept = TrackMoveUtil.getInterception(slope, startLatLng);// 根据点和斜率算取截距 boolean isReverse = (startLatLng.latitude > endLatLng.latitude);// 是不是正向的标示(向上设为正向) double xMoveDistance = isReverse ? TrackMoveUtil.getXMoveDistance(slope) : -1 * TrackMoveUtil.getXMoveDistance(slope); // 应该对经纬度同时处理 double sleep = 0; int flag = 0; for (double j = startLatLng.latitude; !((j >= endLatLng.latitude) ^ isReverse); j = j - xMoveDistance) { // 非暂停状态地图才进行跟随移动 if (pause) { movePause(); } if (stop) { break; } moveing = true; flag++; if (slope != Double.MAX_VALUE) { startLatLng = new LatLng(j, (j - intercept) / slope); } else { startLatLng = new LatLng(j, startLatLng.longitude); } moveCar(startLatLng, mainActivity); moveLine(startLatLng, mainActivity); if (flag % 100 == 0) { moveCamera(startLatLng, mainActivity); } // 如果间隔时间小于1毫秒,则略过当前休眠,累加直到休眠时间到1毫秒:会损失精度 if (mTimeInterval < 1) { sleep += mTimeInterval; if (sleep >= 1) { Log.v(TAG, "sleep:" + sleep); SystemClock.sleep((long) sleep); sleep = 0; } } else { SystemClock.sleep((long) mTimeInterval); } } } long endTime = System.currentTimeMillis(); moveing = false; Log.v(TAG, "endTime:" + endTime); Log.v(TAG, "run mTimeInterval:" + (endTime - startTime)); Log.v(TAG, "moveCoarseTrack end........................................................."); } private void moveLine(LatLng startLatLng, MainActivity mainActivity) { mainActivity.mLatLngList.add(startLatLng);// 向轨迹集合增加轨迹点 mainActivity.mMovePolyline.setPoints(mainActivity.mLatLngList);// 轨迹画线开始 } private void moveCar(LatLng startLatLng, LatLng endLatLng, MainActivity mainActivity) { moveCar(startLatLng,mainActivity); if (mainActivity.mCarMarker != null) { mainActivity.mCarMarker.setRotateAngle((float) TrackMoveUtil.getAngle(startLatLng, endLatLng));// 设置小车车头的方向 } } private void moveCar(LatLng startLatLng,MainActivity mainActivity) { if (mainActivity.mCarMarker != null) { mainActivity.mCarMarker.setPosition(startLatLng);// 小车移动 } } private void movePause() { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } private void moveCamera(LatLng startLatLng, MainActivity mainActivity) { Message message = Message.obtain(); message.what = MainActivity.EventType.MapMove; message.obj = startLatLng; mainActivity.mMainHandler.sendMessage(message); } }
核心算法工具类
* <h1>轨迹平滑所需要的工具方法</h1> Date: 2016-10-27 Created by mxdl */ public class TrackMoveUtil { private static double DISTANCE = 0.0001; /** * 根据两点算斜率 */ public static double getSlope(LatLng fromPoint, LatLng toPoint) { if (fromPoint == null || toPoint == null) { return 0; } if (toPoint.longitude == fromPoint.longitude) { return Double.MAX_VALUE; } double slope = ((toPoint.latitude - fromPoint.latitude) / (toPoint.longitude - fromPoint.longitude)); return slope; } /** * 根据两点算取图标转的角度 */ public static double getAngle(LatLng fromPoint, LatLng toPoint) { if (fromPoint == null || toPoint == null) { return 0; } 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); double angle = 180 * (radio / Math.PI) + deltAngle - 90; return angle; } /** * 根据点和斜率算取截距 */ public static double getInterception(double slope, LatLng point) { if (point == null) { return 0; } return point.latitude - slope * point.longitude; } /** * 计算x方向每次移动的距离 */ public static double getXMoveDistance(double slope) { if (slope == Double.MAX_VALUE) { return DISTANCE; } return Math.abs((DISTANCE * slope) / Math.sqrt(1 + slope * slope)); } /** * 根据轨迹线段计算小车走了多少步 * * @param latLngList * @return */ public static int getStep(List<LatLng> latLngList) { int step = 0; if (latLngList != null && latLngList.size() > 1) { for (int i = 0; i < latLngList.size() - 1; i++) { try { LatLng startPoint = latLngList.get(i); LatLng endPoint = latLngList.get(i + 1); double slope = getSlope(startPoint, endPoint); // 是不是正向的标示(向上设为正向) boolean isReverse = (startPoint.latitude > endPoint.latitude); double xMoveDistance = isReverse ? getXMoveDistance(slope) : -1 * getXMoveDistance(slope); // 应该对经纬度同时处理 for (double j = startPoint.latitude; !((j >= endPoint.latitude) ^ isReverse); j = j - xMoveDistance) { step++; } } catch (Exception e) { e.printStackTrace(); } } } return step; } /** * 根据总距离和步数计算运动时间 * * @param distance * @param step * @return */ public static double getMoveTime(float distance, int step) { double timeInterval = 0; if (distance > 0) { float totalDistance = distance * 1000; if (totalDistance <= 500) { timeInterval = 1000.0 / step; } else if (totalDistance > 500 && totalDistance <= 7500) { timeInterval = 2.0 * totalDistance / step; } else { timeInterval = 15000.0 / step; } } return timeInterval; } /** * 根据轨迹点集合计算总距离 * * @param latLngList * @return */ public static float getDistance(List<LatLng> latLngList) { float distance = 0; if (latLngList != null && latLngList.size() > 1) { for (int i = 0; i < latLngList.size() - 1; i++) { try { distance += AMapUtils.calculateLineDistance(latLngList.get(i), latLngList.get(i + 1)); } catch (Exception e) { e.printStackTrace(); } } } return distance; } // latitude - 地点的纬度,在-90 与90 之间的double 型数值。 // longitude - 地点的经度,在-180 与180 之间的double 型数值。 /** * 根据一个经纬度字符串求一个经纬度集合a|b|c|d; * * @param latlonStr * @return */ public static List<LatLng> getListLatLng(String latlonStr) { if (!TextUtils.isEmpty(latlonStr)) { String[] trackArr = latlonStr.split("\\|"); if (trackArr != null && trackArr.length > 0) { List<LatLng> latLngList = new ArrayList<LatLng>(); for (int i = 0; i < trackArr.length - 1; i = i + 2) { try { String lat = trackArr[i + 1]; String lng = trackArr[i]; // Logger.v(TAG,"trackArr index:" + i); // Logger.v(TAG,"trackArr lat:" + lat); // Logger.v(TAG,"trackArr lng:" + lng); if (!TextUtils.isEmpty(lat) && !TextUtils.isEmpty(lng)) { Double dLat = Double.valueOf(lat); Double dLng = Double.valueOf(lng); if (dLat >= -90 && dLat <= 90 && dLng >= -180 && dLng <= 180 && !(dLat == 0 && dLng == 0)) { LatLng latLng = new LatLng(dLat, dLng); latLngList.add(latLng); } } } catch (Exception e) { e.printStackTrace(); } } return latLngList; } } return null; } }
高德API实现的实时运动轨迹
/** * Description: <MoveCarCustomThread><br> * Author: mxdl<br> * Date: 2019/7/10<br> * Version: V1.0.0<br> * Update: <br> */ public class MoveCarSmoothThread implements IMoveCar { public static final String TAG = MoveCarSmoothThread.class.getSimpleName(); private MovingPointOverlay mMovingPointOverlay; private WeakReference<MainActivity> mActivityWeakReference; private boolean isfirst = true; private MOVE_STATE currMoveState = MOVE_STATE.START_STATUS; public void setCurrMoveState(MOVE_STATE currMoveState) { this.currMoveState = currMoveState; } public MOVE_STATE getCurrMoveState() { return currMoveState; } public MoveCarSmoothThread(MainActivity activity) { mActivityWeakReference = new WeakReference<>(activity); } @Override public void startMove(List<LatLng> latLngs) { if (latLngs == null || latLngs.size() == 0) { return; } Log.v("MYTAG","startMove start:"+Thread.currentThread().getName()); Log.v(TAG, "moveCoarseTrack start........................................................."); long startTime = System.currentTimeMillis(); Log.v(TAG, "startTime:" + startTime); final MainActivity mainActivity = mActivityWeakReference.get(); if (mMovingPointOverlay == null) { mMovingPointOverlay = new MovingPointOverlay(mainActivity.mAMap, mainActivity.mCarMarker); mMovingPointOverlay.setTotalDuration(5); mMovingPointOverlay.setMoveListener(new MovingPointOverlay.MoveListener() { @Override public void move(double v) { if(isfirst){ isfirst = false; Log.v("MYTAG","MoveCarSmoolthThread move start:"+Thread.currentThread().getName()); } LatLng position = mMovingPointOverlay.getPosition(); mainActivity.mLatLngList.add(position);// 向轨迹集合增加轨迹点 mainActivity.mMovePolyline.setPoints(mainActivity.mLatLngList);// 轨迹画线开始 Message message = Message.obtain(); message.what = MainActivity.EventType.MapMove; message.obj = position; message.arg1 = (int)v; mainActivity.mMainHandler.sendMessage(message); } }); } mMovingPointOverlay.setPoints(latLngs); mMovingPointOverlay.startSmoothMove(); long endTime = System.currentTimeMillis(); Log.v(TAG, "endTime:" + endTime); Log.v(TAG, "moveCoarseTrack end........................................................."); } @Override public void reStartMove() { if(mMovingPointOverlay != null){ mMovingPointOverlay.startSmoothMove(); } } @Override public void pauseMove(){ if(mMovingPointOverlay != null){ mMovingPointOverlay.stopMove(); } } @Override public void stopMove(){ if(mMovingPointOverlay != null){ mMovingPointOverlay.destroy(); mMovingPointOverlay = null; } if(mActivityWeakReference.get() != null){ mActivityWeakReference.get().mLatLngList.clear(); } } }
最后我把整个项目的的完整代码传到GitHub上了https://github.com/geduo83/android-amap-movecar
-
论文研究-非线性滤波器在基音轨迹平滑中的应用 .pdf
2019-08-14 17:42:02非线性滤波器在基音轨迹平滑中的应用,安秀红,张雪英,基音是指人们发浊音时声带振动所引起的周期性,声带振动频率的倒数就是基音周期。本文利用经典的自相关函数和平均幅度差函数,把�� -
轨迹平滑方法
2016-11-23 20:49:51主要介绍一下几种平滑方式,并针对三维轨迹进行平滑处理: 1. 滑动平均平滑(Moving average): 邻域内的数据点做平均代替邻域的中心点值,除了一般滑动平均,还有加权滑动平均和指数滑动平均。 2.Savitzky-... -
分享轨迹平滑算法之滑动平均平滑(Moving Average, MA)MATLAB代码
2021-02-27 16:09:16用于一维、二维、三维轨迹平滑(对需要平滑的轴使用该函数即可) 公式 以5点MA平滑为例: ys(i)=12N+1(y(i+N)+y(i+N−1)+…+y(i−N))ys(1)=y(1)ys(2)=(y(1)+y(2)+y(3))/3ys(3)=(y(1)+y(2)+y(3)+y(4)+y(5))/5ys(4)=(y... -
实现运动轨迹_Android车辆运动轨迹平滑移动(高仿滴滴打车)最佳实践
2021-01-11 19:54:00点击上方“Android技术杂货铺”,选择“标星”干货文章,第一时间送达!作者:门心叼龙 链接:https://www.jianshu.com/p/015bd44a56e6关于...一直打算写一篇车辆运动轨迹平滑移动的文章,年后由于工作项目太忙也... -
无动力弹轨迹平滑处理及实现
2020-10-22 00:23:53在现代战争中,随着精确制导武器的广泛使用,飞行控制技术的研究已日趋深入和...这里论述了某无动力弹的飞行控制系统中解算控制率的方法,以及对其弹道临界点的平滑处理,并用数字信号处理器对其算法进行了工程实现。 -
java 轨迹平滑算法_轨迹系列3——通过时间及距离维度进行轨迹聚类平滑的一种方案...
2021-03-09 21:06:361.背景最近项目需求,对轨迹的纠正、信息挖掘、展示等做了一系列的探索性研究。在前面的博客中,写到了基于中值滤波的轨迹纠正...这里我要和大家一起探讨的是在前端如何对轨迹进行平滑的... -
android double精度_Android车辆运动轨迹平滑移动(高仿滴滴打车)最佳实践
2020-11-27 12:49:35点击上方“Android技术杂货铺”,选择“标星”干货文章,第一时间送达!作者:门心叼龙 链接:https://www.jianshu.com/p/015bd44a56e6关于...一直打算写一篇车辆运动轨迹平滑移动的文章,年后由于工作项目太忙也... -
ios 平滑移动view_如何实现轨迹平滑移动
2021-01-12 14:20:45展开全部iOS_MovingAnnotation_Demoannotation移动及转向动画 -查看Demo请打开test.xcworkspace文件使用教程添加MovingAnnotationSource文件夹内代码636...@brief 添加动画@param points 轨迹点串,每个轨迹点为Trac... -
【高德地图SDK】如何实现轨迹平滑移动?
2016-03-31 14:49:57目前市面上大多产品“轨迹平滑移动”做的并不好。 市面上只有快的打车和一号专车实现了平滑移动,那么这是怎么做的呢? -------------------------------------------------------------------------------- -
java 轨迹平滑算法_平滑移动-SDK 示例 | 高德地图API
2021-03-09 21:06:26使用场景出行、运动等类别的app中常常会需要展示车辆或用户的行程轨迹、实时移动轨迹等数据,相应效果需要车辆在地图上平滑移动。该demo展示了如何实现该效果。用到产品核心类/接口类接口说明版本MAMapview- (void)... -
轨迹平滑方法-滑动平均平滑(Moving average)
2020-01-05 18:00:43# 7点2次MA平滑 def MovingAverage(input): output = {} print(input) size = len(input) print(size) i = 0 output[0] = (32.0 * input[0] + 15.0 * input[1] + 3.0 * input[2] - 4.0 * input[3] - 6.0 * ... -
轨迹平滑方法(权重渐变)
2020-03-19 10:41:21clear all; close all; path=[0 0; 1 0; 2 0; 3 0 3 1 3 2 3 3 3 4 4 4 5 4 6 4]; figure for i = 0.1:0.1:0.5 for j = 0.05:0.05:0.2 alp...