python中Google S2算法的简单使用案例

  • 前提: 安装了s2sphere库

程序示例:

# -*- coding: utf-8 -*-
# @Time    : 2023/3/1 下午2:48
# @Author  : Micheal
# @FileName: GoogleS2Util.py
# @Content : 关于Google S2算法的一些基本函数封装
import math
import webbrowser

import s2sphere
import folium


class GoogleS2Util(object):

    # (lat, lng, level=30) -> cell ID
    @classmethod
    def latlng2CellID(cls, lat, lng, level=30):
        ll = s2sphere.LatLng.from_degrees(lat, lng)
        cellId = s2sphere.CellId.from_lat_lng(ll).parent(level).id()  # 指定级数
        return cellId

    # cell ID -> (lat, lng)
    @classmethod
    def cellID2Latlng(cls, cellId):
        ll = s2sphere.CellId(cellId).to_lat_lng()
        point = [ll.lat().degrees, ll.lng().degrees]
        return point

    # cell ID -> (lat, lng)  (推荐使用上面的简便写法)
    @classmethod
    def cellID2Latlng2(cls, cellId):
        cell = s2sphere.Cell(s2sphere.CellId(cellId))
        ll = s2sphere.LatLng.from_point(cell.get_center())
        point = [ll.lat().degrees, ll.lng().degrees]
        return point

    # 判断Cell之间的包含关系:      (cellIdA, cellIdB) -> isContain
    @classmethod
    def cellIsContain(cls, cellIdA, cellIdB):
        return s2sphere.CellId(cellIdA).contains(s2sphere.CellId(cellIdB))

    # 获取 cell 的四个方位:       cell ID -> List<GeoPoint>
    @classmethod
    def cellId2Vertexs(cls, cellId):
        cell = s2sphere.Cell(s2sphere.CellId(cellId))
        points = []
        for i in range(4):
            ll = s2sphere.LatLng.from_point(cell.get_vertex(i))
            points.append([ll.lat().degrees, ll.lng().degrees])
        return points

    # 计算两个Point之间的距离(单位:米): (lat1, lng1, lat2, lng2) -> diatance
    @classmethod
    def getDistance(cls, lat1, lng1, lat2, lng2):
        latLng1 = s2sphere.LatLng.from_degrees(lat1, lng1)
        latLng2 = s2sphere.LatLng.from_degrees(lat2, lng2)
        angle = latLng1.get_distance(latLng2)
        # 弧长 = α(圆心角弧度数)× r(半径)=  n(圆心角)× π(圆周率)× r(半径)/180
        distance = angle.radians * 6371.01 * 1000
        # distance = (angle.degrees * math.pi / 180) * 6371.01 * 1000
        return distance

    # 利用地球经纬度来计算两个坐标点之间的距离
    @classmethod
    def rad(self, ang):
        return math.pi * ang / 180.0
    @classmethod
    def getDistance2(cls, lat1, lng1, lat2, lng2):
        lat1 = cls.rad(lat1)
        lng1 = cls.rad(lng1)
        lat2 = cls.rad(lat2)
        lng2 = cls.rad(lng2)
        dlng = lng2 - lng1
        dlat = lat2 - lat1
        a = (math.sin(dlat / 2)) ** 2
        b = math.cos(lat1) * math.cos(lat2)
        c = (math.sin(dlng / 2)) ** 2
        distance = 6371.01 * 2 * math.asin(math.sqrt(a + b * c)) * 1000.0
        return distance

    # 获取cellid的Level:         cell ID -> level
    @classmethod
    def getLevel(cls, cellId):
        cellID = s2sphere.CellId(cellId)
        return cellID.level()


    # 获取某一 cellID 的所有邻接Cell: (cellID, level) --> List<Long>
    @classmethod
    def getNeighborCells(cls, cellId, level=None):
        if level is None:
            level = cls.getLevel(cellId)
        cellID = s2sphere.CellId(cellId)
        cellANeighbor = [item.id() for item in cellID.get_all_neighbors(level)]
        return cellANeighbor

    # 判断两个(同Level的) cellId 是否相邻
    @classmethod
    def isNeighbor(cls, cellIdA, cellIdB):
        return cellIdA in cls.getNeighborCells(cellIdB)


    # 获取矩形区域内所有的 cell
    # 更多形状区域内的Cell,参考: https://blog.csdn.net/qq_43777978/article/details/116800460
    @classmethod
    def getCoverCells(cls, lat1, lng1, lat2, lng2, minLevel=0, maxLevel=30, maxCells=100):
        # 左下角坐标
        startS2 = s2sphere.LatLng.from_degrees(min(lat1, lat2), min(lng1, lng2))
        # 右上角坐标
        endS2 = s2sphere.LatLng.from_degrees(max(lat1, lat2), max(lng1, lng2))
        rect = s2sphere.LatLngRect(startS2, endS2)  # 矩形区域

        # 获取region区域内的cell
        s2RegionCoverer = s2sphere.RegionCoverer()
        s2RegionCoverer.min_level = minLevel
        s2RegionCoverer.max_level = maxLevel
        s2RegionCoverer.max_cells = maxCells

        covering = s2RegionCoverer.get_covering(rect)
        return [item.id() for item in covering]


if __name__ == "__main__":
    # # 验证 “获取矩形区域内所有的 cell”
    # tiles = 'http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}'  # 蓝黑版
    # myMap = folium.Map([31.374500, 121.487500], zoom_start=12, tiles=tiles, attr='蓝黑版')
    # lat1, lng1, lat2, lng2 = -31.408080852440047, -121.26010348059191, -30.995548292413257, -121.727418244035
    #
    # # 绘制矩形框
    # folium.Polygon(
    #     locations=[[lat1, lng1], [lat1, lng2], [lat2, lng2], [lat2, lng1]],
    #     color="yellow",  # 线条边框颜色
    #     weight=2,  # 线条的宽度
    #     opacity=0.8,  # 线条透明度
    # ).add_to(myMap)
    #
    # # 获取cellIDs
    # cells = GoogleS2Util.getCoverCells(lat1, lng1, lat2, lng2, 1, 30, 100)
    # for cell in cells:
    #     # 绘制矩形框
    #     folium.Polygon(
    #         locations=GoogleS2Util.cellId2Vertexs(cell),
    #         color="yellow",  # 线条边框颜色
    #         weight=2,  # 线条的宽度
    #         opacity=0.1,  # 线条透明度
    #         fill=True,  # 是否填充内部
    #         fill_color="red",  # 内部颜色
    #         fill_opacity=0.5  # 内部颜色透明度
    #     ).add_to(myMap)
    #
    #
    # file_name = "test_debug_analysis.html"
    # myMap.save(file_name)  # 保存
    # webbrowser.get(using='google-chrome').open(file_name, new=2)  # 加载

    # # 是否包含关系
    # loc = GoogleS2Util.cellID2Latlng(3869282349875200000)
    # result = GoogleS2Util.cellIsContain(3869280597528543232, GoogleS2Util.latlng2CellID(loc[0], loc[1], 14))
    # print(result)
    #
    # # 获取 cell 的 4个方位
    # result = GoogleS2Util.cellId2Vertexs(3869280597528543232)
    # print(result)
    #
    # 获取距离
    locA = GoogleS2Util.cellID2Latlng(3869275444641529856)
    locB = GoogleS2Util.cellID2Latlng(3869275455378948096)
    locC = GoogleS2Util.cellID2Latlng(3869281267543441408)
    locA2 = GoogleS2Util.cellID2Latlng2(3869275444641529856)
    locB2 = GoogleS2Util.cellID2Latlng2(3869275455378948096)
    locC2 = GoogleS2Util.cellID2Latlng2(3869281267543441408)
    print(locA, locB, locC)
    print(locA2, locB2, locC2)
    # result = GoogleS2Util.getDistance(locA[0], locA[1], locB[0], locB[1])
    # result2 = GoogleS2Util.getDistance2(locA[0], locA[1], locB[0], locB[1])
    # print(result)
    # print(result2)
    #
    # # 获取级数
    # result = GoogleS2Util.getLevel(3869280597528543232)
    # print(result)
    #
    # # 获取邻居 cell
    # result = GoogleS2Util.getNeighborCells(3869280597528543232, 14)
    # print(result)
    #
    # # 判断是否相邻
    # flag = GoogleS2Util.isNeighbor(3869280597528543232, 3869282315515461632)
    # print(flag)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值