首页 > 其他分享 >GeoHash处理经纬度,降维,空间填充曲线

GeoHash处理经纬度,降维,空间填充曲线

时间:2024-11-10 20:46:18浏览次数:1  
标签:经纬度 经度 longitude 降维 180 GeoHash double

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


参考

https://segmentfault.com/a/1190000042971576

GeoHash原理以及代码实现_geohash编码-CSDN博客

GeoHash代码实现--java_geohash java代码示例-CSDN博客

在线经纬度距离计算

http://geohash.co/

https://geohash.jorren.nl/

简介

Geohash是一种用于标识地理位置的编码方法。它将经纬度坐标转换为一个简短的字符串,这个字符串可以用来表示地球上的任意位置。Geohash的特点是,编码的长度越长,表示的位置就越精确;反之,编码越短,则表示的位置范围就越大。

接下来我们来一起探究一下这是个什么东西,有什么用?

参考的文章讲的也是非常不错,这里就啰嗦整理一下,并引申一下了。

经纬度

首先必须要从经纬度开始,我们都知道为了标记我们在地球上的位置,出现了经纬度,南北方向叫做纬度[-90,90],东西方向是经度[-180,180]。在使用具有定位功能的设备时,通过人造地球卫星就能确定我们在地球上的位置,其使用的都是经纬度。

GeoHash

GeoHash是一种地理编码,就是用于处理经纬度的。其原理是使用空间填充曲线—— Z 阶曲线(Z-order curve),在地球表面的经纬度球面坐标系下,划分出许许多多不规则矩形,并将每个矩形进行编码,表示某个经纬度范围的面,本质上就是一种降维打击方案。

image

如果你对hash比较敏感的话,就会联想到计算机科学中还有很多hashJava顶级父类Objecthashcode,数据结构的hashcode,散列hash算法如:md5hash负载均衡策略,等等。提到这些是为了重复强调一下相比于无序的hash算法,GeoHash是有序的,毕竟它存在的意义就是为了降维,降维是将(x,y)表示的二维坐标系的点转换为一条直线上的点,虽然信息丢失是不可避免的,但是保留信息就是降维的重要目的之一。如下图,将平面划分成矩形,并将其串联起来,最终拉成一条直线,其是有序的,信息从(x,y)变为[起点,终点],实现了降维。

image

结论出发一般会有一个很大的问题:放弃思考,不再问为什么?

提出问题往往是进步的开始!

为什么这样的曲线是可行?空间填充曲线都有什么特点?

我并不能回答所有相关问题,但至少可以知道这样的曲线一定是可微分的,也就是能通过数学表达式表示的。而且其还能一定程度上的转换二维信息,比如:二维坐标系下很重要的距离问题,在降维后通过大小就能判断。

实现原理

经纬度转GeoHash

1、经纬度,按照[-90,90][-180,180]逐渐二分,在左区间为0,在右区间为1,得到二进制编码,具体要得到多少位的二进制,看选取的精度,5位二进制对应1位GeoHash

2、合并经纬度,偶数位放经度,奇数位放纬度,注意第一位是0,放偶数,简单理解,经度纬度经度纬度…叠加

3、每5位对应以为base32编码,转译一下就得到了GeoHash编码

GeoHash转经纬度

反之即可,只是GeoHash代码的是一块区域,转换后的经纬度是区域的中心点的经纬度。

image

参考网站:

http://geohash.co/

https://geohash.jorren.nl/

局限性

GeoHash是有序的,但本质上都是从二维平面到曲线,无论如何都是会丢失信息的。

边界问题

很容易理解,所有的区域划分问题都会存在这样的问题,如下图,相比如参考点,明显红点更近一些,但是通过GeoHash编码,结论就是绿色的点更近。

通常的解决方案是除了本身区域还要使用周围的相邻区域辅助判断计算。

image

非线性问题

要知道我们讨论的是地球这个三维球体的表面,抛开地球本身就是不规则球体不讲,就算是规则,肯定不能完全套用在球面上吧,这本身就不是矩形啊。球面距离公式也不是简单平方差开根号的吧。0纬度的赤道移动一个经度和30纬度移动一个经度差别也是可想而知的。

球面的必然问题

这是不可避免的问题,还是和前面一样的原因,我们目标是球面,其是无边的!

因为我们经纬度的划分规则,体现在了经度上,-180180是一样的一条线。

GeoHash是无法理解-179179是相近的。

image

意义

尽管GeoHash具有一些局限性,但是在现实中还是有很多用处的。

顺带一讲,Redis中的Geo也有使用GeoHash哦!

1、附近,在使用某些带有地图功能的软件时,查找附近距离最近的xxx,有可能就用到了GeoHash哦,原因也很简单,GeoHash极大的加快了检索速度,相比如球面距离计算可想而知对比一串字符串要简单的多。

2、聚集,想要统计某片区域有多少用户,就可以利用GeoHash将经纬度编码,然后取不同位数,做不同精度的统计。

代码实现

下面是优化了性能的代码实现,其中使用了一些位运算,不过效果是一致的。

public class GeoHash {
    /**
     * geoHash 32位
     */
    private static final char[] BASE32 = {'0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'b', 'c', 'd', 'e', 'f', 'g',
            'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r',
            's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};

    /**
     * 纬度范围
     */
    private static final double MIN_LAT = -90.0, MAX_LAT = 90.0;

    /**
     * 经度范围
     */
    private static final double MIN_LON = -180.0, MAX_LON = 180.0;

    /**
     * 将给定的纬度和经度编码为GeoHash字符串,指定精度。
     *
     * @param latitude  纬度[-90,90]
     * @param longitude 经度[-180,180]
     * @param precision 精度[1,12]
     * @return GeoHash字符串
     */
    public static String encode(double latitude, double longitude, int precision) {
        if (latitude < MIN_LAT || latitude > MAX_LAT || longitude < MIN_LON || longitude > MAX_LON) {
            throw new IllegalArgumentException("Latitude and longitude must be within valid ranges.");
        }
        if (precision <= 0 || precision > 12) {
            throw new IllegalArgumentException("precision must between 1 and 12");
        }

        long geoHashBits = 0;
        boolean isEven = true;
        double minLat = MIN_LAT, maxLat = MAX_LAT;
        double minLon = MIN_LON, maxLon = MAX_LON;
        int bitIndex = 0;
        // 每个字符代表5位二进制数
        int requiredBits = precision * 5;
        while (bitIndex < requiredBits) {
            double midValue;
            if (isEven) {
                midValue = (minLon + maxLon) / 2;
                if (longitude > midValue) {
                    geoHashBits |= (1L << (requiredBits - bitIndex - 1));
                    minLon = midValue;
                } else {
                    maxLon = midValue;
                }
            } else {
                midValue = (minLat + maxLat) / 2;
                if (latitude > midValue) {
                    geoHashBits |= (1L << (requiredBits - bitIndex - 1));
                    minLat = midValue;
                } else {
                    maxLat = midValue;
                }
            }
            isEven = !isEven;
            bitIndex++;
        }

        return bitsToBase32(geoHashBits, precision);
    }

    /**
     * 将给定的二进制位转换为GeoHash字符串。
     *
     * @param bits      二进制位
     * @param precision 精度
     * @return GeoHash字符串
     */
    private static String bitsToBase32(long bits, int precision) {
        char[] base32Chars = new char[precision];
        for (int i = 0; i < precision; i++) {
            // Extract 5 bits
            int index = (int) ((bits >>> (i * 5)) & 0x1F);
            base32Chars[precision - i - 1] = BASE32[index];
        }
        return new String(base32Chars);
    }

    /**
     * 将给定的经度和纬度转换为7位GeoHash字符串。
     *
     * @param latitude  纬度[-90,90]
     * @param longitude 经度[-180,180]
     * @return GeoHash字符串
     */
    public static String geoHash7(double latitude, double longitude) {
        return encode(latitude, longitude, 7);
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        // GeoHash 字符串长度
        int precision = 9;
        //30.2549529076, 120.1646161079
        System.out.println(encode(30.2549958229, 120.1647019386, precision));
        System.out.println(geoHash7(30.2549958229, 120.1647019386));
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
    }
}

总结

说到降维,立刻就想到了前几年看的一个视频《一种降维打击的可视化方案》。

https://player.bilibili.com/player.html?bvid=BV1Sf4y147J9&autoplay=0

数学就是基础学科之王,人类进步的重要动力。

不得不说近现代文明是欧美人主导的,而至今欧美人的创造力还是领先的。很早之前我也发过一篇文章,大概有一个结论,基础学科教育无比重要,创新是发展的重要动力。

当未来越来越多的杨辉三角、王氏悖论、华氏定理、杨x材料、张x曲线、宋x射线出来就好了!

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview

标签:经纬度,经度,longitude,降维,180,GeoHash,double
From: https://www.cnblogs.com/wnhyang/p/18538447

相关文章

  • es6 flat 将数组降维方法
    flat()是JavaScript中的一个数组方法,用于将嵌套的数组“拉平”成一个新数组。该方法会递归地“降维”数组,直到指定的深度。语法:arr.flat(depth);depth:可选,表示嵌套数组的“深度”。默认为1。传入一个更大的值,数组会被拉平更多层级。如果传入Infinity,则会将所有嵌套的数......
  • 经纬度转换
    PHP腾讯地图经纬度转百度地图经纬度  中国正常GCJ02坐标---->百度地图BD09坐标腾讯地图用的也是GCJ02坐标@paramdouble$lat纬度@paramdouble$lng经度*/functionConvert_GCJ02_To_BD09($lat,$lng){$x_pi=3.14159265358979324*3000.0/180.0;$x=$ln......
  • Python输入位置的坐标(即经纬度),计算两点的距离结果保留两位
    可以使用haversine公式来计算两个坐标点之间的距离。以下是一个示例代码:importmathdefcalculate_distance(lat1,lon1,lat2,lon2):#将经纬度转换为弧度lon1=math.radians(lon1)lat1=math.radians(lat1)lon2=math.radians(lon2)lat2=m......
  • Qt/C++路径轨迹回放/回放每个点信号/回放结束信号/拿到移动的坐标点经纬度
    一、前言说明在使用百度地图的路书功能中,并没有提供移动的信号以及移动结束的信号,但是很多时候都期望拿到移动的哪里了以及移动结束的信号,以便做出对应的处理,比如结束后需要触发一些对应的操作。经过搜索发现很多人都有这个需求,需要在js文件中加上一点代码才行,也就是在start开始......
  • 深度解析机器学习的四大核心功能:分类、回归、聚类与降维
    深度解析机器学习的四大核心功能:分类、回归、聚类与降维前言分类(Classification):预测离散标签的艺术关键算法与代码示例逻辑回归支持向量机(SVM)回归(Regression):预测连续值的科学关键算法与代码示例线性回归岭回归(RidgeRegression)聚类(Clustering):无监督学习中的分组专家......
  • 基于支持向量机和降维PCA的人脸识别实战
    公众号:尤而小屋编辑:Peter作者:Peter大家好,我是Peter~今天给大家介绍一个基于支持向量机SVM和PCA降维的人脸识别的实战案例,主要包含:人脸数据lfw数据集下载PCA降维基于SVM的分类模型构建模型分类预测结果可视化效果如下图:基于SVM和PCA算法的人脸识别使用数据为fetch_l......
  • .NET程序获取当前IP经纬度,并通过经纬度实现天气查询功能
     创建一个.net8的webapi项目备用 编辑一个实体类,该实体类用于存储获取ip地址的经纬度数据使用 继续编辑三个类,用来存储对应经纬度的具体天气数据包: 改造默认的天气控制器,里面写成我们自己的。例如先写个获取IP的经纬度坐标的请求 运行一下,看下现在的效果,可以看......
  • 什么是降维?
    一、降维的概念    降维是一种减少数据集中特征数量的技术,目的是减少计算复杂性,同时尽量保留原始数据的重要信息。降维通常用于高维数据集,其中可能包含成千上万个特征。降维可以分为两类:一类是特征选择,指从现有特征中选择一个子集的过程,不创建新的特征;另一类是特征提......
  • “降维模糊C均值(PCA-FCM)”创新算法的聚类与可视化
    在这篇博客中,我们将探讨一个MATLAB代码示例,它展示了如何从Excel文件导入数据,进行模糊C均值(FCM)聚类,并通过2D和3D图形可视化聚类结果。让我们一步一步地深入这个过程!1.环境准备首先,我们需要清空工作环境,以确保没有旧变量干扰我们的结果。这可以通过以下几行代码实现:clear;cl......
  • 关于九种降维算法的一份介绍
    在这篇文章中我将介绍有关降维的一些东西,其中包括一些常见降维方法的概念、用途、优缺点以及python代码。一、概念降维是机器学习中常用到的一种技术,其用于减少数据集的维度,但又能保存数据集的重要信息,从而简化数据的处理,并提高计算效率、调高模型的性能以及方便可视化。二......