本身开发微信小程序为主,文中小程序默认指的是微信小程序相关
根据定位计算范围区域和微信步数统计
场景和需求描述
假设为了鼓励老年人锻炼身体,通过授权用户的微信步数并统计当日最高步数,老年人可以通过选择捐赠步数来获取积分。然后可以通过积分兑换礼品,兑换礼品需要进行签到校对,以社区中心半径500米范围作为有效签到。
微信运动数据获取
在uniapp项目的manifest设置授权描述
/* 小程序特有相关 */
"mp-weixin" : {
//....
"permission" : {
"scope.userLocation" : {
"desc" : "授权的位置信息将用于提供定位服务"
}
}
//.....
}
用户授权微信运动权限后,获取encryptedData和iv两个参数的数据 在服务端进行解密开放数据的操作,这里我保存的是解密到当日最高步数,并且以10000步奖励100分作为获取积分的规则进行积分发放
uni.authorize({
scope: 'scope.werun',
success(ress) {
wx.getWeRunData({
success (res) {
const encryptedData = res.encryptedData
const iv = res.iv
// ***
}
})
兑换规则说明
一、老人通过运动步数得到的积分,需要在指定的养老服务中心签到才能换取实物礼品。 二、签到的目的是为了保存老人在养老服务中心的服务记录。 三、签到是有签到范围的,类似于钉钉打卡确保服务中心位置的准确无误。 四、然后通过线上积分兑换后的订单由工作人员校对订单完成最后实物兑换。
获取定位计算签到范围
主要思路:
地球为不规则椭球体,这里将它当成球体计算,误差率在0.3‰左右,可忽略不计。
最终转换为具体数学问题就是:球体上两点的最短距离为经过两点大圆的劣弧长度。
求解思路:经纬度 → 两点坐标(直角坐标系) → 弦长(两点距离) → 弧长
①球体上某个点的三维坐标转换
设
- 地球半径
- 地心到 E 0° N 0° 的连线为
轴
- 地心到 E 90° N 0° 的连线为
轴
- 地心到 E 0° N 90° 的连线为
轴
- 地球表面有一点
, 经度为
, 纬度为
, 单位为弧度
则坐标可表示为:
代码实现
const R = 6371 // 地球半径
const {cos, sin, PI} = Math
let getPoint = (e, n) => {
//首先将角度转为弧度
e *= PI/180
n *= PI/180
reutrn {
x: R*cos(n)*cos(e),
y: R*cos(n)*sin(e),
z: R*sin(n)
}
}
②计算两点坐标距离(三维坐标系)
这个比较简单,只需要两点坐标平方差开根号加绝对值
③根据弦长求弧长
草图
现在已知弦长 , 半径
, 要求弧
的长度
根据草图就比较容易, 只需先求出 的大小 :
代码实现
const {asin} = Math
const R = 6371
r = asin(c/2/R)*2*R
最后合并代码
/**
* 获取两经纬度之间的距离
* @param {number} e1 点1的东经, 单位:角度, 如果是西经则为负
* @param {number} n1 点1的北纬, 单位:角度, 如果是南纬则为负
* @param {number} e2
* @param {number} n2
*/
function getDistance(e1, n1, e2, n2){
const R = 6371
const { sin, cos, asin, PI, hypot } = Math
/** 根据经纬度获取点的坐标 */
let getPoint = (e, n) => {
e *= PI/180
n *= PI/180
//这里 R* 被去掉, 相当于先求单位圆上两点的距, 最后会再将这个距离放大 R 倍
return {x: cos(n)*cos(e), y: cos(n)*sin(e), z: sin(n)}
}
let a = getPoint(e1, n1)
let b = getPoint(e2, n2)
let c = hypot(a.x - b.x, a.y - b.y, a.z - b.z)
let r = asin(c/2)*2*R
return r
}
实际根据定位计算范围距离 获取用户当时坐标和服务端返回的社区坐标 代入getDistance函数计算出距离,判断是否在范围内
getLocation() {
wx.getLocation({
type: 'gcj02',
success: res => {
(this.deflatitude = res.latitude), (this.deflongitude = res.longitude); if(this.param.scope&&this.param.lng&&this.param.lat){
let dis = (getDistance(this.param.lat,this.param.lng,res.latitude,res.longitude)).toFixed(3)*1000
console.log('dis',dis)
this.dis = dis // 范围
}
}
END
念念不忘必有回响,有效的努力,会让你在未来闪闪发光。
本文正在参与「掘金小册免费学啦!」活动,点击查看活动详情。