首页 > 解决方案 > 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

标签: javascriptreact-nativegeohashing

解决方案


推荐阅读