根据经纬度,使用h3算法获取所有方向上的索引,并且按照距离排序

3 篇文章 0 订阅
1 篇文章 0 订阅
文章介绍了H3,一个用于地理空间索引的开源系统,它将地球划分为六边形单元。文章提供了一个Java示例,展示如何引入H3库并使用H3Util工具类进行kRingDistances查询,获取给定点周围多圈的六边形索引。这种方法提高了地理位置查询的效率。
摘要由CSDN通过智能技术生成

Neighboring indexes in all directions, ordered by distance from the origin index.

前言

H3是一个针对地球的空间划分和空间索引系统。

H3地理空间索引系统是一个离散的全局网格系统,该系统由具有层次结构索引的球形多精度六边形拼贴组成。在球形外接二十面体的平面上创建六边形网格系统,然后使用反面为中心的多面体结构投影将网格单元投影到球体的表面。

从单纯的点到点覆盖范围计算,查询效率低下,而Uber H3通过为全球地理位置定制了一套,正六边形构成的覆盖图,每个覆盖图有一个唯一Id,通过空间换时间的思想,让点对点的查询变成了索引结构的匹配查询。实现了在没有巨大误差前提下的高效查询。

参考:

Uber开源H3算法(地理索引)的工程化实现 - 简书

Uber h3算法_小柯行色匆匆的博客-CSDN博客_uber h3

一、h3是什么?

H3是一个地理空间索引系统,它将世界划分为六边形单元。H3在Apache 2许可下是开源的。

二、使用步骤

1.引入库

<dependency>
    <groupId>com.uber</groupId>
    <artifactId>h3</artifactId>
    <version>3.7.1</version>
</dependency>

2.完整代码

h3工具类

package com.tqy.util;

import com.uber.h3core.H3Core;
import com.uber.h3core.util.GeoCoord;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public final class H3Util {
    private H3Util() {
    }

    private static H3Core instance = null;

    /**
     * description
     * 获取H3实例
     * @author tengqingya
     * @date 2022/9/3 16:44
     * @return com.uber.h3core.H3Core
     */
    public static H3Core getInstance() {
        if (instance == null) {
            instance = getH3Core();
        }
        return instance;
    }

    /**
     * description
     * H3单例模式
     * @author tengqingya
     * @date 2022/9/3 16:44
     * @return com.uber.h3core.H3Core
     */
    private static H3Core getH3Core() {
        H3Core h3Core = null;
        try {
            h3Core = H3Core.newInstance();
        } catch (IOException e) {
            h3Core = H3Core.newSystemInstance();
        }
        return h3Core;
    }

    /**
     * description
     * 获取当前位置N圈的六边形索引
     * @param latitude latitude
     * @param longitude longitude
     * @param kRing kRing
     * @author tengqingya
     * @date 2022/9/3 16:45
     * @return java.util.List<java.lang.String>
     */
    public static List<String> kRingDistances(Double latitude, Double longitude, int kRing) {
        H3Core h3Core = getInstance();
        if (Objects.isNull(h3Core)) {
            return new ArrayList<>();
        }
        String h3Address = h3Core.geoToH3Address(latitude, longitude, ConstantsEnum.H3_REVOLUTION7);
        List<List<String>> kRingDistances = h3Core.kRingDistances(h3Address, kRing);
        if (CollectionUtils.isEmpty(kRingDistances)) {
            return Collections.emptyList();
        }
        return kRingDistances.stream().flatMap(Collection::stream).collect(Collectors.toList());
    }

    /**
     * description
     * 获取当前位置N圈的六边形索引,按圈数归并
     * @param latitude latitude
     * @param longitude longitude
     * @param kRing kRing
     * @author tengqingya
     * @date 2022/9/3 16:45
     * @return java.util.List<java.util.List < java.lang.String>>
     */
    public static List<List<String>> kRingDistancesList(Double latitude, Double longitude, int kRing) {
        H3Core h3Core = getInstance();
        if (Objects.isNull(h3Core)) {
            return new ArrayList<>();
        }
        String h3Address = h3Core.geoToH3Address(latitude, longitude, ConstantsEnum.H3_REVOLUTION7);
        //h3Address is like 87309154affffff
        List<List<String>> kRingDistances = h3Core.kRingDistances(h3Address, kRing);
        if (CollectionUtils.isEmpty(kRingDistances)) {
            return Collections.emptyList();
        }
        return kRingDistances;
    }

    /**
     * description
     * 根据半径获取精确度值
     * @param radius radius
     * @author tengqingya
     * @date 2022/8/19 18:52
     * @return int
     */
    public static int getResolution(Integer radius) {
        if (null == radius || radius > ConstantsEnum.INT_4000) {
            radius = ConstantsEnum.INT_4000;
        }
        return radius > ConstantsEnum.INT_2000 ? ConstantsEnum.INT_2 : 1;
    }

    /**
     * H3索引转网格角
     * @param h3Address H3索引
     * @return 网格角
     */
    public static List<GeoCoord> h3ToGeoBoundary(String h3Address) {
        return getInstance().h3ToGeoBoundary(h3Address);
    }
}

枚举类

package com.tqy.util;


public final class ConstantsEnum {

    private ConstantsEnum() {

    }
    public static final Integer H3_REVOLUTION7 = 7;

    /**
     * 地球半径,单位:米
     */
    public static final double ERATH_RADIUS_IN_METER = 6378137d;


    public static final Integer INT_2 = 2;

    public static final int INT_2000 = 2000;


    public static final int INT_4000 = 4000;

}

使用

package com.tqy;

import com.alibaba.fastjson.JSON;
import com.meizu.tqy.util.H3Util;

import java.util.List;

import static java.lang.System.out;

/**
 * @author tengqy
 * @create 2023-01-16 19:59
 */
public class h3 {
    public static void main(String[] args){
        List<List<String>> h3AddressListAll = H3Util.kRingDistancesList(31.932001156316513d, 118.81938553759494d, 3);
        out.println(JSON.toJSONString(h3AddressListAll));
    }
}

输出结果

[["87309154affffff"],["87309155dffffff","873091559ffffff","873091464ffffff","87309154bffffff","873091548ffffff","87309154effffff"],["873091543ffffff","87309155cffffff","873091558ffffff","87309155bffffff","873091466ffffff","873091460ffffff","873091465ffffff","873091096ffffff","873091549ffffff","87309154dffffff","87309154cffffff","873091541ffffff"],["873091540ffffff","873091542ffffff","873091551ffffff","87309155effffff","87309155affffff","873091474ffffff","873091475ffffff","873091462ffffff","873091463ffffff","873091461ffffff","873091092ffffff","873091090ffffff","873091094ffffff","8730910b2ffffff","8730910b6ffffff","87309156bffffff","87309156affffff","873091545ffffff"]]

格式化后如下所示

[
    [
        "87309154affffff"
    ],
    [
        "87309155dffffff",
        "873091559ffffff",
        "873091464ffffff",
        "87309154bffffff",
        "873091548ffffff",
        "87309154effffff"
    ],
    [
        "873091543ffffff",
        "87309155cffffff",
        "873091558ffffff",
        "87309155bffffff",
        "873091466ffffff",
        "873091460ffffff",
        "873091465ffffff",
        "873091096ffffff",
        "873091549ffffff",
        "87309154dffffff",
        "87309154cffffff",
        "873091541ffffff"
    ],
    [
        "873091540ffffff",
        "873091542ffffff",
        "873091551ffffff",
        "87309155effffff",
        "87309155affffff",
        "873091474ffffff",
        "873091475ffffff",
        "873091462ffffff",
        "873091463ffffff",
        "873091461ffffff",
        "873091092ffffff",
        "873091090ffffff",
        "873091094ffffff",
        "8730910b2ffffff",
        "8730910b6ffffff",
        "87309156bffffff",
        "87309156affffff",
        "873091545ffffff"
    ]
]

由于入参传的参数是

H3Util.kRingDistancesList(31.932001156316513d, 118.81938553759494d, 3)

其中3表示需要中心索引周围3圈的数据,所以返回的结果有周围的3层数据,每一层相较于上一层多6个(六边形)


总结

通过使用h3编码,可以将地理位置的范围查询,变为基于六边形的索引的等值或者in值查询,大大降低了查询的复杂度

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值