javascript - React native 和 firestore:geohash 附近搜索到给定距离,结果错误
问题描述
我需要使用geohashs。我必须检查作为 geohash 的目标位置是否在我当前作为 geohash 的位置的范围(距离)内。它确实有效,但我注意到范围差异很大。所以我写了一个测试器,我不需要我的数据库来向你展示问题。
在 GeoTest() 函数中开始阅读我已将起始位置定义为 lat、lon 坐标,并且也编码为 geohash。
然后我以英里为单位输入距离/范围值。
两者我都可以计算下geohashs和上geohashs。
使用上下geohashs,我可以比较其他地方(在firestore中)的geohashs,以检查它们是否在范围内。在这一点上有错误的结果。例如,一个地方在 600 英里的距离内,但在 320 英里处,结果已经在其范围内。那是错误的。
我将上限和下限再次解码为 lat、lon 值,并仅在坐标(而不是 geohash)上计算距离,以向您展示差异,并且距离几乎翻了一番。有时它比因素 2 更高,有时更低。如果我选择不同的距离值,它会有所不同。
在我看来,如果我输入 10 英里的距离,对范围进行编码并对其进行解码以重新计算它应该保持 10 英里的距离。由于四舍五入可能会有一些小的差异,但没有 20.37,这是预期的两倍。
现在的问题是,为什么解码后的距离比以前高了?我是否在任何地方错过了一些计算?
所以我无法准确检查位置是否在给定范围内。
我知道在客户端代码中我只能处理坐标,但是这些地方在 Firestore 中以 geohash 的形式给出,我必须直接从那里获取范围内的地方,而无需在客户端进行过滤。所以这不是一个选择,我认为如果我有正确的数学,它可以工作。谢谢你。
GeoTester.js:
import geohash from "ngeohash";
export const GeoTester = () => {
const getDistance = (startLat, startLon, targetLat, targetLon) => {
const dLat = (startLat-targetLat) * Math.PI / 180;
const dLon = (startLon-targetLon) * Math.PI / 180;
const lat1 = targetLat * Math.PI / 180;
const lat2 = startLat * Math.PI / 180;
const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const d = 6371 * c;
return d;
}
const getGeohashRange = (latitude, longitude, distance) => {
const latDeg = 0.0144927536231884; // degrees latitude per mile
const lonDeg = 0.0181818181818182; // degrees longitude per mile
const lowerLat = latitude - latDeg * distance;
const lowerLon = longitude - lonDeg * distance;
const upperLat = latitude + latDeg * distance;
const upperLon = longitude + lonDeg * distance;
const lowerGeohash = geohash.encode(lowerLat, lowerLon);
const upperGeohash = geohash.encode(upperLat, upperLon);
return { lowerGeohash, upperGeohash };
}
const geoTest = () => {
const startLat = 52.00991050587265;
const startLon = 4.708180705155277;
const startGeohash = geohash.encode(startLat, startLon);
const distance = 10; // miles
const { lowerGeohash, upperGeohash } = getGeohashRange(startLat, startLon, distance);
const lowerDecoded = geohash.decode(lowerGeohash);
const upperDecoded = geohash.decode(upperGeohash);
const distLower = getDistance(startLat, startLon, lowerDecoded.latitude, lowerDecoded.longitude);
const distUpper = getDistance(startLat, startLon, upperDecoded.latitude, upperDecoded.longitude);
const diffLower = (distLower / distance);
const diffUpper = (distUpper / distance);
console.log('distance and diff lower', distLower, diffLower);
console.log('distance and diff upper', distUpper, diffUpper);
}
return {
geoTest
};
}
应用程序.js:
import React from 'react';
import {View, Button} from 'react-native';
import {GeoTester} from '../helpers/GeoTester';
const App = () => {
const { geoTest } = GeoTester();
return (
<View>
<Button title="Test" onPress={() => geoTest()} />
</View>
);
}
export default App;
console.log 输出:
distance and diff lower 20.374469782722997 2.0374469782722997
distance and diff upper 20.347694449540903 2.0347694449540903