手机指北针 + Python绘制徒步路线图
Posted Rolei_zl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手机指北针 + Python绘制徒步路线图相关的知识,希望对你有一定的参考价值。
- 问题:户外活动,深林密林没有信号,无GRPS,手机地图无法使用,无法了解行程和行动路线。
- 需求:绘制户外行动路线,标记关键行程点,留下行走路线图。
- 分析
1)行动路线包括行动方向、行程长度
2)指南针(手持/手机)可以指示和标记行动方向
3)行程长度可以由 行动速度 * 行动时间获得
4)行程关键点标识可以通过外部输入进行标记
5)绘制简单行动路线(手工/程序),示意图,不计精确度 - 设计 -- 最简版
1)使用手机指南针功能
2)记录行走路线方向:沿路线行进方向
3)标记关键行程点方向:线路拐点 + 行程关键标识
4)Python解析关键行程点,绘制行路路线示意图 - 实现
1)界面绘制
2)手机指南针功能调用
3)记录行进方向
4)记录关键行程点// 创建实例时注册方向传感器 Button_Start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /* 定义手机传感器 */ // 获取传感器管理器 sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // 地磁传感器,单位是uT(微特斯拉),测量设备周围三个物理轴(x,y,z)的磁场 masensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); // 加速度传感器,单位是m/s2,测量应用于设备X、Y、Z轴上的加速度 accesensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); /* 注册传感器 */ // 注册地磁传感器 sensorManager.registerListener(sensorEventListener, masensor, SensorManager.SENSOR_DELAY_GAME); // 注册加速度传感器 sensorManager.registerListener(sensorEventListener, accesensor,SensorManager.SENSOR_DELAY_GAME); } }); // 响应传感器监听 SensorEventListener sensorEventListener = new SensorEventListener() { float[] acceleValues = new float[3]; //加速度传感器值 float[] magneticValues = new float[3]; //地磁传感器值 @Override public void onSensorChanged(SensorEvent event) { // 获得传感器值 if(event.sensor.getType() == Sensor.TYPE_ACCELEROMETER){ acceleValues = event.values.clone(); }else if(event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){ magneticValues = event.values.clone(); } float[] values = new float[3]; float[] R = new float[9]; SensorManager.getRotationMatrix(R, null, acceleValues, magneticValues); SensorManager.getOrientation(R, values); // 方向角,以北为正方向 degrees = -(float)Math.toDegrees(values[0]); }; // 记录节点方向 if(diff >= timeinterval) { // 达到时间间隔 // 记录当前时间(日期+时间)和方向角,最新记录最前记录 String st = df.format(curDate.getTime()) + ": " + degrees + "\\n" + etmout.getText().toString(); etmout.setText(st); // 显示在文本框中 curDate = new Date(System.currentTimeMillis()); ct = curDate.getTime(); // 显示时间间隔 tvtest.setText(String.valueOf(et) + " --- " + String.valueOf(ct)); }
手机不识别这是哪里?
好吧,停下自动记录,手工输入吧~~
5)保存行程记录
保存本机还要权限注册和申请,懒,先不做。
好吧,手工拷贝并保存到本机。
6)APP生成/发布
5)调用行程记录使用Python绘图// build.gradle // defaultConfig 增加以下节点,定义生成的APP应用名 android.applicationVariants.all { variant -> variant.outputs.all { outputFileName = "CompassPath.apk" } }
6)显示import math # 数据处理,主要是小数位数 import matplotlib.pyplot as plt # 画图 # 对方向角文件(手机获取并手动何存)进行解析 # 原文件格式:日期、时间、里程方向角、里程点名字 # 记录分解为:日期、时间(小时、分、秒)、里程点方向X轴坐标、里程点方向Y轴坐标、里程点名字 def get_direction(filename): pdate = [] ptime = [] pdirect = [] pname = [] pall = [] # date, hour, min, sec, X_direct-cos, Y_direct-sin, name # 读入文件 with open("./"+filename,"r", encoding='utf-8') as fp: frls = fp.readlines() for fl in frls: pt = [] ## replace all double blank while fl.count(" ")>0: fl = fl.replace(" "," ") pf = fl.split(" ",2) ## NULL or there is no dirction data if fl.strip() == "" or len(pf) < 3: continue else: ## get date pdate.append(pf[0]) pt.append(pf[0]) ## get time and split into hour, minute, second ptime.append(pf[1][0:-1].split(":")) ptpf = pf[1][0:-1].split(":") pt.append(int(ptpf[0])) pt.append(int(ptpf[1])) pt.append(int(ptpf[2])) ## get direction and address point description pdir = pf[2].replace("\\n","").strip() pp = 0 pn = "" for i in pdir: if i.isnumeric() or i == "." or i == "-": continue else: pp = pdir.index(i) break if pp == 0: pd = float(pdir) + 90 pname.append("?") pn = "?" else: pd = float(pdir[0:pp]) + 90 pname.append(pdir[pp:len(pdir)].strip()) pn = pdir[pp:len(pdir)].strip() ## 方向角转成 X,Y轴坐标 pt.append(round(math.cos(math.pi*pd/180),2)) pt.append(round(math.sin(math.pi*pd/180),2)) pt.append(pn) pall.append(pt) pall.reverse() return pall def drawpath(points): px = [] py = [] pname = [] ppx = 0 # perious node x value pcx = 0 # current node x value ppy = 0 # perious node y value pcy = 0 # current node y value ph = 0 # hour pm = 0 # minutes ps = 0 # seconds totaltime = 0 for i in range(0,len(points)): pi = points[i] ph = pi[1] pm = pi[2] ps = pi[3] ptime = 0 # time interval ## 累计路程 X, Y if i > 0: pcx = pi[4] + ppx pcy = pi[5] + ppy ptime = ((ph-points[i-1][1])*60*60 + (pm-points[i-1][2])*60 + (ps-points[i-1][3]))/60 # double length per 30 seconds else: pcx = pi[4] pcy = pi[5] ptime = 1.0 ppx = pcx ppy = pcy totaltime = round(totaltime+ptime,1) px.append(pcx) py.append(pcy) pn = "" if i == 0: pn = "Start: " + pi[6] elif i == len(points)-1: pn = "End: " + pi[6] else: pn = pi[6] pname.append(pn + ", " + str(math.ceil(ptime)) + "'" + ", " + str(totaltime) + "'") ## draw line with points address waypoints = [px, py] plt.plot(waypoints[0], waypoints[1], '^-b', MarkerEdgeColor='g',MarkerFaceColor='g') ## lable name for i in range(0,len(pname)): plt.text(px[i]+0.05,py[i]+0.1,pname[i],ha='center', va='center', color="blue",clip_on=True, fontsize=8) plt.grid(False) ## 坐标轴 plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False) plt.tick_params(axis='y', which='both', left=False, right=False, labelleft=False) ## 解决乱码 plt.rcParams['font.sans-serif'] = ['SimHei'] # aovid wide code ## X,Y轴坐标起点 和 终点设置 plt.xlim(math.floor(min(px)) if min(px)>0 else math.floor(min(px)),math.ceil(max(px)) if max(px)>0 else math.ceil(max(px))) plt.ylim(math.floor(min(py)) if min(py)>0 else math.floor(min(py)),math.ceil(max(py)) if max(py)>0 else math.ceil(max(py))) plt.title(label='地点名,阶段耗时,总耗时(分钟)',loc='left',fontsize=8) plt.show()
大概就是这个样子吧,每隔5秒记录一次方向角。对吗?
实际操作时在关键里程点开始记录方向角,记录后停止,标记里程碑点名字,到下个关键里程点再次记录。
好处?不用手机实时的记录那么多方向点,而且还要标记名字。
似乎这个Time Interval有点鸡肋
- 功能增强
1)待完成功能
* 根据行走时间,动态绘制行进路线中关键行程点的长短
* 其他。。。边用边加
2)文件保存
需要调用和申请手机存储权限,暂不实现
3)手机端直接绘制行程路线图
懒,暂不实现
4)行程高度获取
等手机有了压力感应器再说,暂不实现
以上是关于手机指北针 + Python绘制徒步路线图的主要内容,如果未能解决你的问题,请参考以下文章