在已知的二维坐标里找到最接近的点

news2025/1/9 19:06:45

一、业务场景

最近在研发的项目,在做可视化层,在全球地图上,对我们的国家的陆地地图经纬度按照步长为1的间隔做了二维处理。在得到一组整数的点位信息后,需要将我们已有的数据库数据(业务项目)按照地址的经纬度,映射到这些点位上,找到对应的id建立联系。简化后的处理逻辑如下:
在这里插入图片描述
参考上图:
纬度为y轴,跨度为35,间距为1
经度为x轴,跨度为61,间距为1
橙色的点为业务项目对应的经纬度信息(x’,y’)
需要计算出二维坐标中整数点上最靠近的点(利用三角形三边公式)
MIN(aa + bb)
第一层:粉色层
第二层:灰色层

由于我们国家的地图存在边界,并不是一个规规矩矩的4方形,且我国的内陆海渤海的包围圈,海洋地区并不计入在二维坐标中,跨度为1的情况下,会出现项目对应的坐标点,需要一层一层对外查找的情况。
在这里插入图片描述

二、点位数据

CREATE TABLE `china_grid_map` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增主见',
  `lng` decimal(20,6) NOT NULL COMMENT '经度',
  `lat` decimal(20,6) NOT NULL COMMENT '纬度',
  PRIMARY KEY (`id`),
  KEY `idx_lat` (`lng`),
  KEY `idx_lng` (`lat`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='自定义中国陆地地图网格经纬度信息';

部分示例数据

INSERT INTO china_grid_map (id, lng, lat) VALUES (1, 74.000000, 39.000000),(3, 74.000000, 40.000000),(4, 75.000000, 37.000000),(5, 75.000000, 38.000000),(7, 75.000000, 39.000000),(9, 75.000000, 40.000000),(11, 76.000000, 37.000000),(13, 76.000000, 38.000000),(15, 76.000000, 39.000000),(17, 76.000000, 40.000000),(18, 77.000000, 36.000000),(20, 77.000000, 37.000000),(22, 77.000000, 38.000000),(24, 77.000000, 39.000000),(26, 77.000000, 40.000000),(28, 77.000000, 41.000000),(30, 78.000000, 36.000000),(32, 78.000000, 37.000000),(34, 78.000000, 38.000000),(36, 78.000000, 39.000000),(38, 78.000000, 40.000000),(40, 78.000000, 41.000000),(42, 79.000000, 32.000000),(44, 79.000000, 34.000000),(46, 79.000000, 35.000000),...
(1911, 131.000000, 44.000000),(1913, 131.000000, 45.000000),(1915, 131.000000, 46.000000),(1917, 131.000000, 47.000000),(1920, 132.000000, 46.000000),(1922, 132.000000, 47.000000),(1925, 133.000000, 46.000000),(1927, 133.000000, 47.000000),(1929, 133.000000, 48.000000),(1930, 134.000000, 47.000000),(1932, 134.000000, 48.000000);

三、实现方式

v1.0 版本 MySQL-直取数据

假设要求的项目坐标点为:
{“lat”: “31.231706”, “lng”: “121.472644”}
第一版本:
直接利用sql,查找出最靠近的四个点,然后再计算距离。

select id, lng, lat
from china_grid_map
where lat <= (select lat as latright from china_grid_map where lat >= 31.231706 order by lat limit 1)
  and lat >= (select lat as latleft from china_grid_map where lat <= 31.231706 order by lat desc limit 1)
  and lng <= (select lng as lngright from china_grid_map where lng >= 121.472644 order by lng limit 1)
  and lng >= (select lng as lngLeft from china_grid_map where lng <= 121.472644 order by lng desc limit 1);

如果查到了点 就求出最小的距离对应的点
如果没查到,重复上面点查询,扩大点数

存在的问题:
1.SQL复杂,如果点位正好在边界上,无论扩充多少层都查不到数据
2.耗时久

v2.0 版本 redis-Zset

{“lat”: “31.231706”, “lng”: “121.472644”}
已经知道步长为1,所以最靠近的点,如图1中所示,直接对x’,y’向下向上取整,组合。

利用redis缓存,使用Zset模型
key存储序列化后的信息,score用经度值
利用Zset的对经度范围取值,score (x,x+1)
对返回的数据再挨个查找,找出映射的id

存在的问题:
1.耗时久,因为按照经度 (x,x+1)取值 还是会得到很多数据,需要循环对比数据 才能得到对应的id
2.批量导入数据时,需要反反复复的从redis中取数据

v3.0 版本 内存-HashMap

Map<String,Long> CACHE = new HashMap<>();
key = lat + “-” + lng
value = id

按照步骤二的模式获取到点列表后,从map中get(key);
如果第一层4个点未命中,扩大到第二层

存在的问题:
1.存在内存中,分布式系统部署,每台服务器上的内存各自独立[好在该点位信息一旦生成后不会修改,在项目初始化后,不存在插入、删除相关的操作,只要考虑查询的时间效率]
2.791个点,消耗的存储比较大:113944

v4.0 版本 内存-二维数组 long[][]

由于点位是提前知道不会变动,且是步长为1的有规则的数据
经度数据区间 : 74 - 134 总个数 61
纬度数据区间 : 19 - 53 总个数 35

private static long[][] GRID_ARRAY = new long[61][35]; 

在项目启动时初始化缓存数据

public void initCacheByArray() {
        //先获取到所有的点位数据
        List<GridMapDO> mapDOS = baseMapper.listAllDO();
        if (CollectionUtil.isEmpty(mapDOS)) {
            return;
        }

        //循环将数据放入到缓存中
        for (GridMapDO grid : mapDOS) {
            int arrayLng = getArrayLng(grid.getLng());
            int arrayLat = getArrayLat(grid.getLat());
            if (arrayLng == -1 || arrayLat == -1) {
                //存在越界的点位
                log.info(">>>>>>>>>存在越界点位[经度:{},纬度:{}],跳过缓存<<<<<<<", grid.getLng(), grid.getLat());
                continue;
            }
            //找到对应的位置 将id存储为数组的值
            GRID_ARRAY[arrayLng][arrayLat] = grid.getId();
        }

        log.info(">>>> 缓存结束,缓存内容:[{}] <<<<<<", JSONObject.toJSONString(GRID_ARRAY));

    }

private int getArrayLng(BigDecimal lng) {
        //防止数组下标越界
        int intLng = lng.intValue();
        if (intLng < 74 || intLng > 134) {
            return -1;
        }
        return lng.intValue() - 74;
    }

    private int getArrayLat(BigDecimal lat) {
        int intLat = lat.intValue();
        if (intLat < 19 || intLat > 53) {
            return -1;
        }
        return lat.intValue() - 19;
    }

用的时候 只需要计算出点位,直接从数组中取对应的下标即可。
如果 GRID_ARRAY[x][y] == 0L 说明点位不是中国的大陆地图
如果 GRID_ARRAY[x][y] != 0L 计算出该点的距离平方

存在的问题:
1.存在内存中,分布式系统部署,每台服务器上的内存各自独立[好在该点位信息一旦生成后不会修改,在项目初始化后,不存在插入、删除相关的操作,只要考虑查询的时间效率]
2.791个点,消耗的存储比V3.0版本减少了1个数量级,但是数组用的是连续的存储空间

四、总结

可以多尝试,找出最合适项目的,结合数据的规律,空间换时间 等等
只有实践了 才能找到最佳的吧…

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用ArcGIS Pro自动矢量化道路

对于已经制作好的电子地图&#xff0c;我们可以通过像素识别的方式将其中的要素提取出来&#xff0c;比如本教程要讲到的道路数据&#xff0c;这里为大家介绍一下在ArcGIS Pro中如何自动矢量化道路&#xff0c;希望能对你有所帮助。 栅格计算 在工具箱中点击“Spatial Analys…

全国职业技能大赛云计算--高职组赛题卷⑤(容器云)

全国职业技能大赛云计算--高职组赛题卷⑤&#xff08;容器云&#xff09; 第二场次题目&#xff1a;容器云平台部署与运维任务2 基于容器的web应用系统部署任务&#xff08;15分&#xff09;任务3 基于容器的持续集成部署任务&#xff08;15分&#xff09;任务4 Kubernetes容器…

IntelliJ IDEA使用——常规设置

文章目录 版本说明主题设置取消检查更新依赖自动导入禁止import xxx.*、允许import内部类显示行号、方法分割线、空格代码提示&#xff08;匹配所有字母&#xff09;自定义注释颜色添加头部注释自定义字体设置字符编码关联本地GitJDK编译版本Maven配置Tomcat配置代码注释设置头…

37.流光溢彩的渐变加载条动画效果

特效 源码 index.html <!DOCTYPE html> <html> <head> <title>Glowing Gradient Loading Animation</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body><…

DEA一直updating index,这样无法使用其内部各种方法跳转,而且持续时间特别长

IDEA一直updating index&#xff0c;这样无法使用其内部各种方法跳转&#xff0c;而且持续时间特别长 解决方案 点击File菜单&#xff0c;点击子菜单Invalid Caches,弹出弹窗后选择Invalid Caches And Restart重启后就可以了 问题原因 分析了一下&#xff0c;这次引起的原因…

leetcode543 二叉树的直径

题目 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由它们之间边数表示。 示例 输入&#xff1a;root [1,2,3,4,5] 输出&#xff1…

从追问AI到人机融合再到人机环境系统智能

人工智能与人类的多元价值对齐是一个复杂而重要的问题。虽然人工智能系统具有强大的计算和学习能力&#xff0c;但它们缺乏人类的情感、道德判断和伦理意识。然而&#xff0c;以下几个方面可以帮助实现人工智能与人类的多元价值对齐&#xff1a;&#xff08;1&#xff09;制定明…

【AI视野·今日NLP 自然语言处理论文速览 第三十五期】Mon, 18 Sep 2023

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 18 Sep 2023 Totally 51 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers "Merge Conflicts!" Exploring the Impacts of External Distractors to Parametric Knowledge Gra…

自动化测试—选择器

根据id选择名字&#xff1a; <input type"text" idsearchtext />element wd.find_element(By.CSS_SELECTOR, #searchtext) element.send_keys(你好)根据class选择元素的两种方式&#xff1a; 1.By.CLASS_NAME&#xff1a; elements wd.find_elements(By.…

C语言每日一题(7):获得月份天数

文章主题&#xff1a;获得月份天数&#x1f525;所属专栏&#xff1a;C语言每日一题&#x1f4d7;作者简介&#xff1a;每天不定时更新C语言的小白一枚&#xff0c;记录分享自己每天的所思所想&#x1f604;&#x1f3b6;个人主页&#xff1a;[₽]的个人主页&#x1f3c4;&…

MySQL数据库操作以及sql语句总结

一、MySQL数据库知识点补充 一个数据库就是一个完整的业务单元&#xff0c;可以包含多张表&#xff0c;数据被存储在表中在表中为了更加准确的存储数据&#xff0c;保证数据的正确有效&#xff0c;可以在创建表的时候&#xff0c;为表添加一些强制性的验证&#xff0c;包括数据…

day29IO流(其他流)

1. 缓冲流 昨天学习了基本的一些流&#xff0c;作为IO流的入门&#xff0c;今天我们要见识一些更强大的流。比如能够高效读写的缓冲流&#xff0c;能够转换编码的转换流&#xff0c;能够持久化存储对象的序列化流等等。这些功能更为强大的流&#xff0c;都是在基本的流对象基础…

【Proteus仿真】【STM32单片机】数字秒表设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 系统运行后&#xff0c;数码管默认不显示&#xff0c;当按下K1按下后&#xff0c;启动计时&#xff1b; 可按下K2键记录时间&#xff0c;可记录3次。也可再按下K1键停止&#xff0c;再次按下K1键继续运行…

【记录成长】大学时光已过半, 分享我的大二暑期实习经历

你好&#xff0c;我是cpt&#xff0c;本文章记录我大二暑期找实习的过程&#xff0c;以及工作中的点点滴滴&#xff0c;还有一些经验分享&#xff0c;希望能够帮助到你。 实习投递 (BOSS 1k沟通 10面) 投递 我是2023.6.16 才开始投递的 当时真的很晚了 基本很少hc 而且小公司…

Vuex —— 状态管理 | Module

在前面讲到了关于Vuex数据状态管理的内容&#xff0c;讲了Vuex的五大核心属性&#xff0c;在这五大核心属性中就 state、mutation 和 actions 在前面介绍 Vuex 状态管理和讲 Vuex 中的同步和异步操作已经比较熟悉了&#xff0c;getter 是基于state 的计算属性&#xff0c;vue 中…

用青龙面板实现阿里云盘每日签到

什么是青龙面板 ? 青龙面板 是支持 Python3、JavaScript、Shell、Typescript 的定时任务管理平台。 青龙面板从功能上看&#xff0c;和群晖的 计划任务 很像&#xff0c;都可以定时执行一个任务&#xff0c;并发送通知&#xff0c;只是青龙面板更强大一些。 安装 在群晖上以…

【校招VIP】测试计划之系统测试

考点介绍&#xff1a; 系统测试是将经过测试的子系统装配成一个完整系统来测试。它是检验系统是否确实能提供系统方案说明书中指定功能的有效方法。测试重点是整个系统的运行以及与其他软件的兼容性。 测试计划之系统测试-相关题目及解析内容可点击文章末尾链接查看&#xff…

静力水准仪的安装方式

监测系统的安装 概括 初次安装监测系统时&#xff0c;需结合现场施工情况遵循先后主次的顺序操作&#xff0c;合理的规划安装顺序可避免安装过程的失误造成的返工&#xff1b; 正常顺序为&#xff1a; 1.确定测量基准点的位置和监测点的位置并作出标记&#xff1b; 2.对基…

引入ojdbc6 11.2.0.3版本

IntelliJ IDEA使用Maven导入一些依赖包&#xff0c;在pom.xml中引入ojdbc6 11.2.0.3版本一直失败&#xff0c;下载不了.jar文件 <dependency><groupId>com.oracle</groupId><artifactId>ojdbc6</artifactId><version>11.2.0.3</version…

【Linux】分布式版本控制工具git

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…