Initial commit of akmon project
This commit is contained in:
218
doc_chat/位置.md
Normal file
218
doc_chat/位置.md
Normal file
@@ -0,0 +1,218 @@
|
||||
明白了。你想把“2.4G 网关 + 手环 RSSI”估算出的位置信息接到地图里,在 uni-app-x(UTS Android)上怎么做更稳当。下面给你一套实用建议和可直接复用的代码骨架(包含精度圈、外部地图打开、国标坐标处理等)。
|
||||
|
||||
## 建议与实践路径
|
||||
|
||||
- 定位算法侧(从 RSSI 到坐标)
|
||||
- 用对数路径损耗模型把 RSSI 转成距离:d = 10^((RSSI0 − RSSI) / (10·n));n 在室内一般 2.2–3.0,需要场地标定得到 RSSI0 和 n。
|
||||
- 融合多网关:
|
||||
- 简单稳健:加权质心(WCL),权重用 1/d^p 或用 RSSI 线性/指数映射,抗多径比三边定位更鲁棒。
|
||||
- 条件好时:三边定位(最小二乘)+ RANSAC 剔除离群网关。
|
||||
- 平滑与抗抖动:3–5 点中值滤波 + 指数滑动平均,或一维/二维卡尔曼滤波。
|
||||
- 场景约束:将估算点“吸附”到建筑内合法区域、多边形(map matching),并给出不确定性半径(例如距离方差/残差→半径)。
|
||||
|
||||
- 坐标系问题(中国大陆必须重视)
|
||||
- 如果你算出的是 WGS84(GPS 原生),大多数国内地图(高德/腾讯/微信小程序/原生 <map>)使用 GCJ-02(火星坐标)。展示前请转换为 GCJ-02。
|
||||
- 反向地理编码(坐标→地址)可用高德/腾讯等服务,注意密钥与限频,不要在前端暴露密钥。
|
||||
|
||||
- uni-app-x(UTS Android)地图接入的三种方式
|
||||
1) 快速方案:uni.openLocation 打开系统/第三方地图
|
||||
- 最快、稳定;不在应用内嵌地图,适合查看/导航跳转。
|
||||
2) 应用内嵌地图:内置 `<map>` 组件
|
||||
- App-Android 通常可用 markers/circles/polyline;在 uni-app-x 某些版本上功能覆盖可能比标准 uni 稍有限,如遇不支持的属性可退化或走插件方案。
|
||||
3) UTS 原生插件(高德/腾讯地图 SDK)
|
||||
- 需要更高级能力(离线地图、室内图、海量点渲染、轨迹回放、热力图),建议用官方原生 SDK 的 UTS 插件。去 uni 原生插件市场搜索“高德地图 UTS/定位 UTS”等。
|
||||
|
||||
- 工程与性能建议
|
||||
- 权限:Android 申请 ACCESS_FINE_LOCATION;在 manifest.json 的 app-plus 节点配置权限。
|
||||
- 绑定简化:模板里避免函数调用和复杂表达式,预先计算好 markers/circles 字段(已按 UTS 规范给出示例)。
|
||||
- 批量更新:频繁刷新时做节流/合并更新,避免每条数据都 setData。
|
||||
- 可视化:用 circle 显示“不确定性半径”;锚点颜色代表置信度;支持点击 marker 查看详情。
|
||||
|
||||
## 可复用代码片段
|
||||
|
||||
### 1) 坐标转换(WGS84 → GCJ-02,UTS 版)
|
||||
|
||||
```ts
|
||||
// utils/coord.uts
|
||||
export function wgs84ToGcj02(lat: number, lng: number): number[] {
|
||||
if (outOfChina(lat, lng)) return [lat, lng]
|
||||
const dLat = transformLat(lng - 105.0, lat - 35.0)
|
||||
const dLng = transformLng(lng - 105.0, lat - 35.0)
|
||||
const radLat = lat / 180.0 * Math.PI
|
||||
let magic = Math.sin(radLat)
|
||||
magic = 1 - 0.00669342162296594323 * magic * magic
|
||||
const sqrtMagic = Math.sqrt(magic)
|
||||
const dLat2 = (dLat * 180.0) / ((6335552.717000426 * magic) / (sqrtMagic) * Math.PI)
|
||||
const dLng2 = (dLng * 180.0) / ((6378245.0 / sqrtMagic * Math.cos(radLat)) * Math.PI)
|
||||
return [lat + dLat2, lng + dLng2]
|
||||
}
|
||||
|
||||
function outOfChina(lat: number, lng: number): boolean {
|
||||
return (lng < 72.004 || lng > 137.8347 || lat < 0.8293 || lat > 55.8271)
|
||||
}
|
||||
function transformLat(x: number, y: number): number {
|
||||
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x))
|
||||
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0
|
||||
ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0
|
||||
ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0
|
||||
return ret
|
||||
}
|
||||
function transformLng(x: number, y: number): number {
|
||||
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x))
|
||||
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0
|
||||
ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0
|
||||
ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0
|
||||
return ret
|
||||
}
|
||||
```
|
||||
|
||||
使用建议:如果你算出来的是 WGS84,就先 `wgs84ToGcj02` 再喂给地图组件/服务。
|
||||
|
||||
### 2) 最快路径:外部地图打开(openLocation)
|
||||
|
||||
```vue
|
||||
<!-- pages/location/open.uvue -->
|
||||
<template>
|
||||
<view class="page">
|
||||
<button class="btn" @click="open">在地图中查看</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
export default {
|
||||
data() { return { name: '手环估计位置', lat: 31.23037, lng: 121.4737 } },
|
||||
methods: {
|
||||
open() {
|
||||
// 确保已转换到 GCJ-02(如果在中国大陆)
|
||||
const name = this.name
|
||||
const latitude = this.lat
|
||||
const longitude = this.lng
|
||||
uni.openLocation({ latitude, longitude, name } as any)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.page{ padding: 24rpx }
|
||||
.btn{ padding: 16rpx 24rpx; border:1px solid #ddd; border-radius: 8rpx }
|
||||
</style>
|
||||
```
|
||||
|
||||
- 优点:零集成、稳定、导航能力强。
|
||||
- 缺点:不在应用内展示。
|
||||
|
||||
### 3) 嵌入式地图(内置 `<map>` 组件,展示 marker + 精度圈)
|
||||
|
||||
注意:不同 uni-app-x 版本对 `<map>` 的支持程度略有差异。若你的环境不支持该组件,请选择 openLocation 或 UTS 插件路线。
|
||||
|
||||
```vue
|
||||
<!-- pages/location/map.uvue -->
|
||||
<template>
|
||||
<view class="page">
|
||||
<map class="map"
|
||||
:latitude="centerLat"
|
||||
:longitude="centerLng"
|
||||
:scale="18"
|
||||
:markers="markers"
|
||||
:circles="circles">
|
||||
</map>
|
||||
<view class="toolbar">
|
||||
<button @click="recenter">回到中心</button>
|
||||
<button @click="openSysMap">外部地图</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
import { wgs84ToGcj02 } from '@/utils/coord.uts'
|
||||
|
||||
type MapMarker = {
|
||||
id: number; latitude: number; longitude: number;
|
||||
iconPath: string; width: number; height: number; callout?: any
|
||||
}
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
centerLat: 31.23037,
|
||||
centerLng: 121.4737,
|
||||
markers: [] as Array<MapMarker>,
|
||||
circles: [] as Array<any>,
|
||||
// 原始估算(WGS84)
|
||||
estLat: 31.23037,
|
||||
estLng: 121.4737,
|
||||
// 不确定性半径(米),可用 RSSI 残差/方差计算
|
||||
radius: 20
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.refreshDisplay()
|
||||
},
|
||||
methods: {
|
||||
refreshDisplay() {
|
||||
// 估算坐标→ GCJ-02
|
||||
const r = wgs84ToGcj02(this.estLat, this.estLng)
|
||||
const lat = r[0] as number
|
||||
const lng = r[1] as number
|
||||
this.centerLat = lat
|
||||
this.centerLng = lng
|
||||
// 标点
|
||||
this.markers = [{
|
||||
id: 1,
|
||||
latitude: lat,
|
||||
longitude: lng,
|
||||
iconPath: '/static/marker.png',
|
||||
width: 32, height: 32,
|
||||
callout: { content: '手环估计位置', color: '#000', display: 'ALWAYS' }
|
||||
}]
|
||||
// 精度圈
|
||||
this.circles = [{
|
||||
latitude: lat,
|
||||
longitude: lng,
|
||||
radius: this.radius,
|
||||
color: '#3b82f680',
|
||||
fillColor: '#3b82f633',
|
||||
strokeWidth: 2
|
||||
}]
|
||||
},
|
||||
recenter() {
|
||||
this.refreshDisplay()
|
||||
},
|
||||
openSysMap() {
|
||||
uni.openLocation({ latitude: this.centerLat, longitude: this.centerLng, name: '手环估计位置' } as any)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page{ display:flex; flex-direction: column; height:100% }
|
||||
.map{ flex:1; width:100% }
|
||||
.toolbar{ padding: 12rpx; border-top:1px solid #eee; display:flex; gap: 12rpx }
|
||||
</style>
|
||||
```
|
||||
|
||||
要点(UTS/uni-app-x 规范友好):
|
||||
- 模板里用简单绑定;数据在 data/方法中预先整理,不在模板做复杂表达式。
|
||||
- 属性名、数组结构与 `<map>` 组件文档保持一致;一次性替换 `markers/circles`,避免频繁小更新。
|
||||
|
||||
### 4) UTS 原生插件路线(当你需要更强能力)
|
||||
- 场景:内置 `<map>` 组件受限、需要室内图/离线地图/大量覆盖物/轨迹回放/热力图等。
|
||||
- 做法:在 uni 原生插件市场搜索“高德地图 UTS/定位 UTS”等,选择维护活跃的插件。
|
||||
- 优点:更强渲染与能力接入;缺点:体积与集成复杂度上升。
|
||||
|
||||
## 权限与清单(Android)
|
||||
- manifest.json 中的 app-plus > android > permission 添加定位权限(通常 uni 默认已包含)。首次进入地图页或获取定位前提示授权。
|
||||
- 若做后台定位或持续上传,需额外前台服务与权限申明,注意隐私合规。
|
||||
|
||||
## UI/交互建议
|
||||
- 展示“估计位置 + 不确定性半径”:用户能感知误差而非认为是“点精确到米”。
|
||||
- 支持点击 marker 查看当前 RSSI 源信息(网关数、残差、权重),便于排障。
|
||||
- 多手环时,颜色/形状区分,支持列表一键定位到某个手环。
|
||||
- 大量点位更新做节流(例如 500ms 合并一次),减少渲染压力。
|
||||
|
||||
---
|
||||
|
||||
如果你愿意,我可以在仓库里加一个 `pages/location` 示例页(含坐标转换工具 `utils/coord.uts`),并把你 RSSI 解算出的结果(WGS84)接上这个页面,页面内展示 marker 与精度圈,同时提供“一键外部地图打开”。你只需要告诉我:页面路由名、是否用内置 `<map>` 还是先用 `openLocation` 路线即可。
|
||||
|
||||
Similar code found with 2 license types
|
||||
Reference in New Issue
Block a user