高德地图python地理编码和geopandas应用判断坐标点空间位置

在本人另一篇文章(高德地图地理编码python(版本3.9)爬虫(含坐标转换及数据表模板)-CSDN博客)的基础上增加geopandas功能,使脚本能自动根据查找的高德地图坐标与现有的几何范围进行交互,根据坐标计算距离和判断是否在几何范围内,并将WGS84坐标和距离信息填写在表格中:

如发现问题欢迎指正,如有需求和交流请联系Q:775915005

增加功能包括:1.geopandas表格连接,将范围的几何坐标信息连接到表格

2.坐标转换,平面与经纬度坐标互转

3..判断提供的范围是否多对象,判断坐标点是否在提供的范围(譬如园区)内,如果不在范围内则计算到范围的平面距离

4.根据表格地点名称或地址查找高德地图的坐标,如果查出多个坐标,则计算提供的范围最短距离的坐标

5.根据提供的几何范围生成随机坐标(按需使用)

完整示例及说明:

示例文件下载:【免费】高德地图python地理编码和geopandas应用判断坐标点空间位置示例文件资源-CSDN文库

带编号的企业原始表格数据(共同字段名YQBH)

带编号的几何范围(共同字段名YQBH)

最终生成表格和对应的shp,距离为0表示在YQBH对应的几何范围内

完整代码:(207-209行按实际情况修改)

# -*- coding:utf-8 -*-
# ---------------------------------------------------------------------------
# Author: LGZ
# Created on: 
# Reference:
# coding:cp936 or coding:utf-8
# ---------------------------------------------------------------------------

import logging, os, pprint

import pandas as pd
import numpy as np

# import arcpy
# import itertools, random, math

errfile = r"C:\SoftWare\ArcGISPro\bin\Python\ErrorRecord\ex.txt"
loggingfile = r"C:\SoftWare\ArcGISPro\bin\Python\ErrorRecord\lg.txt"

# logging.disable(logging.CRITICAL)  #禁用CRITICAL级别以下的日志记录
# 按此格式显示DEBUG级别以上的日志记录
# logging.basicConfig(filename=loggingfile, level=logging.DEBUG, format="%(asctime)s-%(levelname)s-%(message)s")
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s-%(levelname)s-%(message)s")

def logprint(*shape):
    return logging.debug(pprint.pformat([*shape]))

# file =
# if os.path.isfile(file):  # 判断文件是否已存在,已存在则删除
#     os.unlink(file)
# if os.path.dirname(file) == "" :  # 判断是否没有完整路径
#     file = os.getcwd()+"//"+file  # 如没有则连接工作目录制造完整路径
# file_list=os.listdir(file)  # 根据需要的文件类型获取目录下文件名列表
# file_list=[i for i in file_list if i.endswith("xlsx") and \  
# not i.startswith("~$")]

# save_fold = 
# os.makedirs(save_fold, exist_ok=True)  # 根据文件夹是否已存在制造文件夹
import math

x_pi = float(3.14159265358979324 * 3000.0 / 180.0)
# //pai
pi = float(3.1415926535897932384626)
# //离心率
ee = float(0.00669342162296594323)
# //长半轴
a = float(6378245.0)
# //经度转换
def transformlat(lng:float, lat:float)-> float:
    ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * math.sqrt(abs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lat * pi) + 40.0 * math.sin(lat / 3.0 * pi)) * 2.0 / 3.0
    ret += (160.0 * math.sin(lat / 12.0 * pi) + 320 * math.sin(lat * pi / 30.0)) * 2.0 / 3.0
    return ret


# //纬度转换
def transformlng(lng:float, lat:float)-> float:
    ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * math.sqrt(abs(lng))
    ret += (20.0 * math.sin(6.0 * lng * pi) + 20.0 * math.sin(2.0 * lng * pi)) * 2.0 / 3.0
    ret += (20.0 * math.sin(lng * pi) + 40.0 * math.sin(lng / 3.0 * pi)) * 2.0 / 3.0
    ret += (150.0 * math.sin(lng / 12.0 * pi) + 300.0 * math.sin(lng / 30.0 * pi)) * 2.0 / 3.0
    return ret
# //国测局转84
def gcj02towgs84(lng:float, lat:float)-> list:
    dlat = transformlat(lng - 105.0, lat - 35.0)
    dlng = transformlng(lng - 105.0, lat - 35.0)
    radlat = lat / 180.0 * pi
    magic = math.sin(radlat)
    magic = 1 - ee * magic * magic
    sqrtmagic = math.sqrt(magic)
    dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * pi)
    dlng = (dlng * 180.0) / (a / sqrtmagic * math.cos(radlat) * pi)
    mglat = lat + dlat
    mglng = lng + dlng
    return [lng * 2 - mglng, lat * 2 - mglat]

def requrl(name:str,ADDRESS:str,geo,key,city,XJQ):

    OUTPUT = 'JSON'
    nameparams = {
        'city': city,  # 修改为对应城市名称
        'address': name,
        'key': key,  # 修改为自己注册的高德地图key
        'output': OUTPUT}
    ADDRESSparams = {
        'city': city,  # 修改为对应城市名称
        'address': ADDRESS,
        'key': key,  # 修改为自己注册的高德地图key
        'output': OUTPUT}

    nameurl = "https://restapi.amap.com/v3/geocode/geo?parameters"
    namej = json.loads(requests.get(nameurl, nameparams).content)
    namelst = []
    ADDRESSurl = "https://restapi.amap.com/v3/geocode/geo?parameters"
    ADDRESSj = json.loads(requests.get(ADDRESSurl, ADDRESSparams).content)
    ADDRESSlst = []
    # if j['status'] == '1' and int(j['count']) >= 1:

    # 使用名称
    if namej['status'] == '1':
        poislst = namej['geocodes']
        for i in range(len(poislst)):  # 能查出多少个POI
            if poislst[i]['district'] == XJQ:  # 是否在白云区内

                location = poislst[i]['location'].split(',')
                lng, lat = map(float, location)

                # 进行转换为平面坐标
                x, y = transformer_plane.transform(gcj02towgs84(lng, lat)[0], gcj02towgs84(lng, lat)[1])

                point = Point(x, y)
                polygon = geo
                distance_to_boundary = distance_to_multipolygon_boundary(polygon, point)
                namelst.append((gcj02towgs84(lng, lat)[0], gcj02towgs84(lng, lat)[1],distance_to_boundary))  # 将经纬坐标和距离放进列表

                logprint(f"The distance from the namepoint to the polygon boundary is {distance_to_boundary:.2f} meters.")
        namelst.sort(key=lambda x: x[2])  # 按照距离排序
        logprint(namelst)
    # 使用地址
    if ADDRESSj['status'] == '1':
        geocodeslst = ADDRESSj['geocodes']
        for i in range(len(geocodeslst)):  # 能查出多少个geocodes
            if geocodeslst[i]['district'] == XJQ:  # 是否在白云区内

                location = geocodeslst[i]['location'].split(',')
                lng, lat = map(float, location)

                # 进行转换为平面坐标
                x, y = transformer_plane.transform(gcj02towgs84(lng, lat)[0], gcj02towgs84(lng, lat)[1])

                point = Point(x, y)
                polygon = geo
                distance_to_boundary = distance_to_multipolygon_boundary(polygon, point)
                ADDRESSlst.append(
                    (gcj02towgs84(lng, lat)[0], gcj02towgs84(lng, lat)[1], distance_to_boundary))  # 将经纬坐标和距离放进列表

                logprint(f"The distance from the ADDRESSpoint to the polygon boundary is {distance_to_boundary:.2f} meters.")
        ADDRESSlst.sort(key=lambda x: x[2])  # 按照距离排序
        logprint(ADDRESSlst)
    if len(ADDRESSlst) > 0 and len(namelst) > 0:
        if namelst[0][2] < ADDRESSlst[0][2]:
            return ["使用名称",str(namelst[0][0]), str(namelst[0][1]), str(namelst[0][2])]
        else:
            return ["使用地址",str(ADDRESSlst[0][0]), str(ADDRESSlst[0][1]), str(ADDRESSlst[0][2])]
    elif len(ADDRESSlst) > 0 and len(namelst) == 0:
        return ["使用地址",str(ADDRESSlst[0][0]), str(ADDRESSlst[0][1]), str(ADDRESSlst[0][2])]
    elif len(ADDRESSlst) == 0 and len(namelst) > 0:
        return ["使用名称",str(namelst[0][0]), str(namelst[0][1]), str(namelst[0][2])]
    else:
        return ["未查询到", "", "", ""]



def generate_random_point(polygon):
    minx, miny, maxx, maxy = polygon.bounds
    while True:
        # 在多边形的边界框内生成随机坐标
        point = Point(random.uniform(minx, maxx), random.uniform(miny, maxy))
        # 检查这个点是否在多边形内部(包括边界)
        if polygon.contains(point) or polygon.touches(point):
            x, y = transformer_longlat.transform(point.x, point.y)
            return [x, y]

def distance_to_multipolygon_boundary(multipolygon, point):
    # 检查是否为MultiPolygon
    if isinstance(multipolygon, MultiPolygon):
        # 初始化最小距离为无穷大
        min_distance = np.inf
        for polygon in multipolygon.geoms:
            if polygon.contains(point):
                return 0
            # 计算点到当前多边形边界的距离
            distance = polygon.exterior.distance(point)
            # 更新最小距离
            if distance < min_distance:
                min_distance = distance
        return min_distance
    elif hasattr(multipolygon, 'exterior'):
        # 如果是单个Polygon,则直接计算距离
        if multipolygon.contains(point):
            return 0
        return multipolygon.exterior.distance(point)
    else:
        raise TypeError("The geometry is neither a Polygon nor a MultiPolygon.")



if __name__ == '__main__':
    """脚本单独使用时运行以下内容"""
    """----------------------------------------------"""
    """---------------------PARA---------------------"""

    try:
        logprint("start of program")
        # TODO
        import random
        import requests, json, time
        import openpyxl
        from pyproj import Transformer
        import geopandas as gpd
        import pandas as pd
        from shapely.geometry import Point,MultiPolygon

        transformer_plane = Transformer.from_crs("EPSG:4490", "EPSG: 4526", always_xy=True)
        transformer_longlat = Transformer.from_crs("EPSG:4526", "EPSG:4490", always_xy=True)
        KEY = '***'  # 修改为对应高德Key
        city = '广州市'  # 修改为对应城市名称
        XJQ = '白云区'  # 修改为对应县级区名称


        dbfpath = r".\无坐标的企业数据0126.xls"
        shppath = r".\范围.shp"
        outpathshp = r".\新增企业坐标20250126BF.shp"
        outpathxlsx = r".\新增企业坐标20250126BF.xlsx"

        # read
        dbfdata = pd.read_excel(dbfpath)  # 需要读取全路径
        shpdata = gpd.read_file(shppath, encoding='gbk')  # 需要读取全路径
        # dbfdata.drop(columns=['geometry'], inplace=True)
        mergedf = pd.merge(dbfdata, shpdata, how='left', on=['YQBH'])
        # mergedfhead = mergedf.head(10)
        mergedfhead = mergedf
        logprint(mergedfhead)

        for index, row in mergedfhead.iterrows():
            logprint(f"Index: {index}")
            name = row["企业名称"]
            ADDRESS = row["地址"]
            geo = row["geometry"]
            # logprint( f"geo.bounds:{geo.bounds}")
            result = requrl(name, ADDRESS, geo, KEY, city, XJQ)
            # result = requrlpoi_add(name, ADDRESS, geo)
            mergedfhead.at[index, "备注"] = result[0]
            mergedfhead.at[index, "经度"] = result[1]
            mergedfhead.at[index, "纬度"] = result[2]
            mergedfhead.at[index, "距离"] = result[3]
            random_point = generate_random_point(geo)
            mergedfhead.at[index, "随机经度"] = random_point[0]
            mergedfhead.at[index, "随机纬度"] = random_point[1]

        pprint.pprint(mergedfhead)
        gdf = gpd.GeoDataFrame(mergedfhead, geometry='geometry')
        gdf.to_file(outpathshp, encoding='gbk')
        gdf.to_excel(outpathxlsx, engine='openpyxl',index=False)
        # gdf.to_csv(outpathcsv, encoding='gbk',index=False)



        # assert a != 0, "a不能为0"
        # raise Exception("XX")

    except Exception as ex:
        # If an error occurred, print line number and error message
        import traceback
        import sys

        tb = sys.exc_info()[2]
        print("捕获到的异常信息是:{}".format(ex))  # 或者使用print("捕获到的异常信息是:",ex.args[0]或者str(ex)或者直接ex);3.9版本ex.message已不可用)
        print("捕获到的异常代码行号是:Line {0}".format(tb.tb_lineno))
        print(traceback.format_exc())  # 显示完整错误路径
        # with open(errfile, "a") as err:
        #     err.write(traceback.format_exc())
        #     print("将traceback信息写入文件成功")
    # except arcpy.ExecuteError:
    # print(arcpy.GetMessages())

    # 无错误运行else后代码
    else:
        logprint("program success")
        # arcpy.AddMessage("program success")

    # 有没有错误均运行finally后代码
    finally:
        pass

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966210.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Pygame介绍与游戏开发

提供pygame功能介绍的文档&#xff1a;Pygame Front Page — pygame v2.6.0 documentation 基础语法和实现逻辑 与CLI不同&#xff0c;pygame提供了图形化使用界面GUI&#xff08;graphical user interface&#xff09;基于图像的界面可以创建一个有图像和颜色的窗口 要让py…

Unity VideoPlayer播放视屏不清晰的一种情况

VideoPlayer的Rnder Texture可以设置Size,如果你的视屏是1920*1080那么就设置成1920*1080。 如果设置成其他分辨率比如800*600会导致视屏不清晰。

使用PyCharm创建项目以及如何注释代码

创建好项目后会出现如下图所示的画面&#xff0c;我们可以通过在项目文件夹上点击鼠标右键&#xff0c;选择“New”菜单下的“Python File”来创建一个 Python 文件&#xff0c;在给文件命名时建议使用英文字母和下划线的组合&#xff0c;创建好的 Python 文件会自动打开&#…

02.06 网络编程_套接字

思维导图&#xff1a; 网络编程基础&#xff1a;套接字的使用 网络编程是现代软件开发中不可或缺的一部分&#xff0c;而套接字&#xff08;Socket&#xff09;是网络编程中用于实现不同主机间通信的基本工具。本文将详细介绍套接字的概念、创建方法、如何通过套接字发送和接…

< OS 有关 > Ubuntu 版本升级 实践 24.04 -> 24.10, 安装 .NET

原因&#xff1a; 想安装 .NET 9 去编译 GitHut 项目&#xff0c;这回用不熟悉的 Ubuntu来做&#xff0c;不知道怎么拐去给 Ubuntu 升级&#xff0c;看到现在版本是 24.10 但不是 LTS 版本&#xff0c;记录下升级过程。 一、实践过程&#xff1a; 1. 查看当前版本 命令1: l…

VsCode创建VUE项目

1. 首先安装Node.js和npm 通过网盘分享的文件&#xff1a;vsCode和Node&#xff08;本人电脑Win11安装&#xff09; 链接: https://pan.baidu.com/s/151gBWTFZh9qIDS9XWMJVUA 提取码: 1234 它们是运行和构建Vue.js应用程序所必需的。 1.1 Node安装&#xff0c;点击下一步即可 …

音频进阶学习十二——Z变换一(Z变换、收敛域、性质与定理)

文章目录 前言一、Z变换1.Z变换的作用2.Z变换公式3.Z的状态表示1&#xff09; r 1 r1 r12&#xff09; 0 < r < 1 0<r<1 0<r<13&#xff09; r > 1 r>1 r>1 4.关于Z的解释 二、收敛域1.收敛域的定义2.收敛域的表示方式3.ROC的分析1&#xff09;当 …

分布式微服务系统架构第91集:系统性能指标总结

加群联系作者vx&#xff1a;xiaoda0423 仓库地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ 系统性能指标总结 系统性能指标包括哪些&#xff1f; 业务指标、资源指标、中间件指标、数据库指标、前端指标、稳定性指标、批量处理指标、可扩展性指标、可靠性指标。 …

【C语言标准库函数】指数与对数函数:exp(), log(), log10()

目录 一、头文件 二、函数简介 2.1. exp(double x) 2.2. log(double x) 2.3. log10(double x) 三、函数实现&#xff08;概念性&#xff09; 3.1. exp(double x) 的模拟实现 3.2. log(double x) 和 log10(double x) 的模拟实现 四、注意事项 4.1. exp(double x) 的注…

CSS Overflow 属性详解:控制内容溢出的利器

在前端开发中&#xff0c;处理内容溢出是一个常见的需求。CSS 提供了 overflow 属性&#xff0c;帮助我们控制当内容超出元素框时的显示方式。本文将详细介绍 overflow 属性的各种取值及其应用场景。 1. 什么是 overflow 属性&#xff1f; overflow 属性用于控制当元素的内容…

go语言中的接口

接口简介 现实生活中的接口 现实生活中手机、相机、U 盘都可以和电脑的 USB 接口建立连接。我们不需要关注 usb 卡槽大小是否一样&#xff0c;因为所有的 USB 接口都是按照统一的标准来设计的。 Golang 中的接口&#xff08;interface&#xff09; Golang 中的接口是一种抽象…

网络安全威胁框架与入侵分析模型概述

引言 “网络安全攻防的本质是人与人之间的对抗&#xff0c;每一次入侵背后都有一个实体&#xff08;个人或组织&#xff09;”。这一经典观点概括了网络攻防的深层本质。无论是APT&#xff08;高级持续性威胁&#xff09;攻击、零日漏洞利用&#xff0c;还是简单的钓鱼攻击&am…

Redis企业开发实战(三)——点评项目之优惠券秒杀

目录 一、全局唯一ID (一)概述 (二)全局ID生成器 (三)全局唯一ID生成策略 1. UUID (Universally Unique Identifier) 2. 雪花算法&#xff08;Snowflake&#xff09; 3. 数据库自增 4. Redis INCR/INCRBY 5.总结 (四)Redis实现全局唯一ID 1.工具类 2.测试类 3…

Verilog代码实例

Verilog语言学习&#xff01; 文章目录 目录 文章目录 前言 一、基本逻辑门代码设计和仿真 1.1 反相器 1.2 与非门 1.3 四位与非门 二、组合逻辑代码设计和仿真 2.1 二选一逻辑 2.2 case语句实现多路选择逻辑 2.3 补码转换 2.4 7段数码管译码器 三、时序逻辑代码设计和仿真 3.1…

排序算法--基数排序

核心思想是按位排序&#xff08;低位到高位&#xff09;。适用于定长的整数或字符串&#xff0c;如例如&#xff1a;手机号、身份证号排序。按数据的每一位从低位到高位&#xff08;或相反&#xff09;依次排序&#xff0c;每次排序使用稳定的算法&#xff08;如计数排序&#…

图形化界面MySQL(MySQL)(超级详细)

目录 1.官网地址 1.1在Linux直接点击NO thanks…? 1.2任何远端登录&#xff0c;再把jj数据库给授权 1.3建立新用户 优点和好处 示例代码&#xff08;MySQL Workbench&#xff09; 示例代码&#xff08;phpMyAdmin&#xff09; 总结 图形化界面 MySQL 工具大全及其功能…

C++ 使用CURL开源库实现Http/Https的get/post请求进行字串和文件传输

CURL开源库介绍 CURL 是一个功能强大的开源库&#xff0c;用于在各种平台上进行网络数据传输。它支持众多的网络协议&#xff0c;像 HTTP、HTTPS、FTP、SMTP 等&#xff0c;能让开发者方便地在程序里实现与远程服务器的通信。 CURL 可以在 Windows、Linux、macOS 等多种操作系…

mapbox进阶,添加绘图扩展插件,绘制圆形

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️MapboxDraw 绘图控件二、🍀添加绘图扩…

网络工程师 (24)数据封装与解封装

一、数据封装 数据封装是指将协议数据单元&#xff08;PDU&#xff09;封装在一组协议头和尾中的过程。在OSI 7层参考模型中&#xff0c;数据从应用层开始&#xff0c;逐层向下封装&#xff0c;直到物理层。每一层都会为其PDU添加相应的协议头和尾&#xff0c;以包含必要的通信…

OSPF基础(3):区域划分

OSPF的区域划分 1、区域产生背景 路由器在同一个区域中泛洪LSA。为了确保每台路由器都拥有对网络拓扑的一致认知&#xff0c;LSDB需要在区域内进行同步。OSPF域如果仅有一个区域&#xff0c;随着网络规模越来越大&#xff0c;OSPF路由器的数量越来越多&#xff0c;这将导致诸…