Hilbert编码 思路和scala 代码

需求:

使用Hilbert 曲线对遥感影像瓦片数据进行编码,获取某个区域的编码值即可

Hilbert 曲线编码方式

思路

大致可以对四个方向的数据进行归类

  1. 左下
  2. 左上
  3. 右上
  4. 右下

这个也对应着编码的顺序

思考在不同Hilbert深度(阶)情况下的四个区域的取值范围

  1. 左下

    [ 0 , 4 n − 1 ) [0,4^{n-1}) [0,4n1)

  2. 左上

    [ 4 n − 1 , 2 × 4 n − 1 ) [4^{n-1}, \ 2\ \times \ 4^{n-1}) [4n1, 2 × 4n1)

  3. 右上

    [ 2 × 4 n − 1 , 3 × 4 n − 1 ) [2\ \times\ 4^{n-1},3 \times4^{n-1}) [2 × 4n1,3×4n1)

  4. 右下

    [ 3 × 4 n − 1 , 4 n ) [3 \ \times \ 4^{n-1}, 4^n) [3 × 4n1,4n)

因此可以使用递归的方式来进行生成数据

主要问题

左上角和右上角不需要做旋转操作

 // 左上角,待判定点不需要做任何调整,直接递归新子区域即可case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt// 右上角case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt

左下角和左上角需要考虑旋转问题

可以使用举例子的方式,来找到旋转后的关系

假设空间区域的左下角坐标为(10,20),右上角的坐标为(20,30),中心坐标为(15, 25)

同样以二阶图为例

这里点位置变更主要针对的是待判定的位置属于哪个区域!

Hilbert 编码区域左下区域(左侧为原始点位置,右侧为旋转后的点位置)

(18,22.5)=> (12.5,28)

(17.5,22) => (12,27.5)

Hilbert 编码区域右下区域

(12,27.5)=>(12.5, 28)

(12.5, 22) => (18, 27.5)

左下旋转后坐标生成方式

原始点位置-中心点位置 = (a,b)

结果 = 中心点位置 + (b,a)

例:(18,22.5) - (15,25) = (3,-2.5)

结果 = (15,25 ) + (-2.5, 3) = (12.5, 28)

右下旋转后坐标生成方式

原始点位置-中心点位置 = (a,b)

结果 = 中心点位置 -(b,a)

例: (12, 27.5) - (15,25) = (-3,2.5)

结果 = (15,25) -(2.5,-3) = (12.5,28)

思路捋清之后,可以考虑代码

// 左下角,case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)// 右下角case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt

需要对待判定点重新生成,但区域的经纬坐标可以不变,我们不关系点坐标怎么变换,我们只是需要最终的编码结果,保证递归正常运行即可

Hilbert 源码生成

input:

  1. 正方形边界两个对角顶点的坐标
  2. 最大Hilbert 层级(阶、深度)
  3. 待判定的区域两点坐标(或者是一个点)

output:

该区域(区域也是计算区域的中心点位置)、点所在的Hilbert 编码值

递归函数

recursiveHilbertEncode

  def recursiveHilbertEncode(point: Point, bounds:(Point,Point), maxLevel:Int): Int = {if (maxLevel == 1)return 0// 边界中心点val lat_half = (bounds._1.lat + bounds._2.lat) / 2 //xval lon_half = (bounds._1.lon + bounds._2.lon) / 2 //y// 反转差值val lat_reverse = point.lat - lat_halfval lon_reverse = point.lon - lon_half(point.lat < lat_half, point.lon < lon_half) match {// 右上角 , p1,p2 不需要动,需要动的是边界和case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt// 右下角 向左旋转case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt//左上case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt// 左下角 向右旋转case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)}}

完整代码

测试代码没整理,有两个main函数,一个是零散的编码区域,一个是从0-15区域的编码结果

import HilbertCurve.getTileCodeobject HilbertCurve {case class Point(lat: Double, lon: Double)// 递归查看Hilbert编码/*** 瓦片中心点坐标* 新bounds边界(其实也是用来定义边界的中心点的)* maxLevel* @return*/def recursiveHilbertEncode(point: Point, bounds:(Point,Point), maxLevel:Int): Int = {if (maxLevel == 1)return 0// 边界中心点val lat_half = (bounds._1.lat + bounds._2.lat) / 2 //xval lon_half = (bounds._1.lon + bounds._2.lon) / 2 //y
//
//    println("边界中心点  :(" + lat_half + ", " + lon_half + ")")
//
//    println("瓦片中心点:(" + point.lat + ", " + point.lon + ")")// point 为瓦片的中心点// 反转差值val lat_reverse = point.lat - lat_halfval lon_reverse = point.lon - lon_half(point.lat < lat_half, point.lon < lon_half) match {// 右上角 , p1,p2 不需要动,需要动的是边界和case (false, false) =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), bounds._2), maxLevel - 1) + 2 * Math.pow(4, maxLevel - 2).toInt//TODO: 问题// 右下角 向左旋转// 此处需要也对point 点进行旋转吗?,好像不需要,这里是沿着中轴线旋转180度case (false, true)  =>recursiveHilbertEncode(Point(lat_half - lon_reverse,lon_half - lat_reverse), ((Point(lat_half,bounds._1.lon),Point(bounds._2.lat,lon_half))), maxLevel - 1) + 3 * Math.pow(4, maxLevel-2).toInt//左上case (true, false)  =>recursiveHilbertEncode(point, (Point(lat_half, lon_half), Point(bounds._1.lat,bounds._2.lon)), maxLevel - 1 ) +   Math.pow(4, maxLevel-2).toInt//TODO: 左下角也有问题// 左下角 向右旋转case (true, true)   =>recursiveHilbertEncode(Point(lat_half + lon_reverse,lon_half + lat_reverse),   (bounds._1, Point(lat_half, lon_half)),maxLevel - 1)}}// 第一步函数:获取瓦片编码def getTileCode(p1: Point, p2: Point, bounds: (Point, Point), maxLevel: Int): Int = {// TODO:此处也默认 bounds 第一个点位于左下角// TODO: 此处默认p1 位于p2的左下角// 定义中心点 x,y值val x_half = (p1.lat + p2.lat)/2val y_half = (p1.lon + p2.lon)/2// 边界的中心点val encoder = recursiveHilbertEncode(Point(x_half,y_half), bounds, maxLevel)encoder}/*** 测试左下角的16个区域* @param args*/def main2(args: Array[String]): Unit = {val bounds = (Point(10.0, 10.0), Point(20.0, 20.0))val maxLevel4 = 4// TODO: 左下角//  15 Error//     最左下角的四个,但是此时如果是旋转过,再去查看右上角和左下角,就会有旋转问题
//val p1 = Point(10,10)val p2 = Point(11.25,11.25)val tileCode0 = getTileCode(p1,p2,bounds,maxLevel4)println(s"TIle Code0 is given region :$tileCode0")val p3 = Point(10,11.25)val p4 = Point(11.25,12.5)val tileCode1 = getTileCode(p3,p4,bounds,maxLevel4)println(s"TIle Code1 is given region :$tileCode1")val p5 = Point(11.25,11.25)val p6 = Point(12.5,12.5)val tileCode2 = getTileCode(p5,p6,bounds,maxLevel4)println(s"TIle Code2 is given region :$tileCode2")val p7 = Point(11.25,10)val p8 = Point(12.5,11.25)val tileCode3 = getTileCode(p7, p8, bounds, maxLevel4)println(s"TIle Code3 is given region :$tileCode3")println("==================")val a = Point(12.5,10)val b = Point(13.75,11.25)val tileCode4 = getTileCode(a, b, bounds, maxLevel4)println(s"TIle Code4 is given region :$tileCode4")val t1 = Point(13.75,10)val t2 = Point(15.0, 11.25)val tileCode5 = getTileCode(t1,t2,bounds,maxLevel4)println(s"Tile Code5 is given region:$tileCode5")val c = Point(13.75,11.25)val d = Point(15,12.5)val tileCode6 = getTileCode(c,d,bounds,maxLevel4)println(s"TIle Code6 is given region :$tileCode6")val b3 = Point(12.5,11.25)val b4 = Point(13.75,12.5)val tileCode7 = getTileCode(b3,b4,bounds,maxLevel4)println(s"TIle Code7 is given region :$tileCode7")println("=================")val e = Point(12.5 ,12.5)val f = Point(13.75, 13.75)val tileCode8 = getTileCode(e,f,bounds,maxLevel4)println(s"TIle Code8 is given region :$tileCode8")val g = Point(13.75, 12.5)val h = Point(15,13.75)val tileCode9 = getTileCode(g, h,bounds, maxLevel4)println(s"TIle Code9 is given region :$tileCode9")val c3 = Point(12.5,13.75)val c4 = Point(13.75,15)val tileCode11 = getTileCode(c3,c4, bounds, maxLevel4)println(s"TIle Code11 is given region :$tileCode11")
//     左下角的左上角的右上角有问题println("==========")val c1 = Point(11.25,13.75)val c2 = Point(12.5,15)val tileCode12 = getTileCode(c1,c2,bounds,maxLevel4)println(s"TIle Code12 is given region :$tileCode12")val d1 = Point(11.25,12.5)val d2 = Point(12.5,13.75)val tileCode13 = getTileCode(d1,d2,bounds,maxLevel4)println(s"TIle Code13 is given region :$tileCode13")val d3 = Point(10,12.5)val d4 = Point(11.25,13.75)val tileCode14 = getTileCode(d3,d4,bounds,maxLevel4)println(s"TIle Code14 is given region :$tileCode14")val d5 = Point(10,13.75)val d6 = Point(11.25,15)val tileCode15 = getTileCode(d5,d6,bounds,maxLevel4)println(s"TIle Code15 is given region :$tileCode15")// TODO; 右下角TODO Error// 58
//    val p74 = Point(15,10)
//    val p84 = Point(16.25,11.25)
//    val tileCode44 = getTileCode(p74, p84, bounds, maxLevel4)
//    println(s"Tile Code for given region: $tileCode44")}def main(args: Array[String]): Unit = {val bounds = (Point(10.0, 10.0), Point(20.0, 20.0))// 右上角  42val p14 = Point(18.75, 18.75)val p24 = Point(20, 20)val maxLevel4 = 4val tileCode14 = getTileCode(p14, p24, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode14")// 左上角 //21val p34 = Point(10, 18.75)val p44 = Point(11.25, 20)val tileCode24 = getTileCode(p34, p44, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode24")//   5val p54 = Point(13.75, 10)val p64 = Point(15, 11.25)val tileCode34 = getTileCode(p54, p64, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode34")// TODO 15 Errorval p545 = Point(10, 13.75)val p645 = Point(11.25, 15)val tileCode344 = getTileCode(p545, p645, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode344")// 右下角// TODO Error// 58val p74 = Point(15,10)val p84 = Point(16.25,11.25)val tileCode44 = getTileCode(p74, p84, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode44")// 34val p1 = Point(16.25, 16.25)val p2 = Point(17.5, 17.5)val maxLevel = 3val tileCode = getTileCode(p1, p2, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode")// 10val p3 = Point(13.75, 13.75)val p4 = Point(15.0, 15.0)val tileCode2 = getTileCode(p3, p4, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode2")// 8val p5 = Point(12.5, 12.5)val p6 = Point(13.75, 13.75)val tileCode3 = getTileCode(p5, p6, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode3")// 32val p7 = Point(15.0, 15.0)val p8 = Point(16.25, 16.25)val tileCode4 = getTileCode(p7, p8, bounds, maxLevel4)println(s"Tile Code for given region: $tileCode4")}
}

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

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

相关文章

【fastadmin开发实战】经营数据自动识别录入

项目场景描述&#xff1a;每日录入各个门店的员工经营数据&#xff0c;直接从微信复制报数、系统识别录入。 解决方案&#xff1a;各个门店按照固定的汇报模板进行汇报&#xff08;如福田店有员工1、2、3、4、5号员工&#xff0c;每个员工按模板报数&#xff09; 例如&#xf…

JMH320【亲测】【御剑九歌】唯美仙侠手游御剑九歌+WIN学习手工端+视频教程+开服清档+运营后台+授权GM物品充值后台

资源介绍&#xff1a; 这也是仙梦奇缘的一个游戏 注意&#xff1a;外网14位IP或域名 ———————————————————————————————————– ps后台介绍: 1区运营后台&#xff1a;http://ip:9981/admin/admintool/ 2区运营后台&#xff1a;http://ip…

Day44:LeedCode 188.买卖股票的最佳时机IV 309.最佳买卖股票时机含冷冻期 714.买卖股票的最佳时机含手续费

188. 买卖股票的最佳时机 IV 给你一个整数数组 prices 和一个整数 k &#xff0c;其中 prices[i] 是某支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说&#xff0c;你最多可以买 k 次&#xff0c;卖 k 次。 注意&…

[深度学习]卷积理解

单通道卷积 看这个的可视化就很好理解了 https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md 多通道卷积 当输入有多个通道时,卷积核需要拥有相同的通道数. 假设输入有c个通道,那么卷积核的每个通道分别于相应的输入数据通道进行卷积,然后将得到的特征图对…

51单片机STC89C52RC——14.1 直流电机调速

目录 目的/效果 1&#xff1a;电机转速同步LED呼吸灯 2 通过独立按键 控制直流电机转速。 一&#xff0c;STC单片机模块 二&#xff0c;直流电机 2.1 简介 2.2 驱动电路 2.2.1 大功率器件直接驱动 2.2.2 H桥驱动 正转 反转 2.2.3 ULN2003D 引脚、电路 2.3 PWM&…

智能光伏开发都能用到什么软件和工具?

随着全球对可再生能源的日益重视和光伏技术的快速发展&#xff0c;智能光伏开发已成为推动能源转型的重要力量。在光伏项目的全生命周期中&#xff0c;从设计、建设到运营管理&#xff0c;各种软件和工具的应用发挥着至关重要的作用。 一、光伏系统设计软件 1、PVsyst PVsyst…

Linux 端口

什么是虚拟端口 计算机程序之间的通讯&#xff0c;通过IP只能锁定计算机&#xff0c;但是无法锁定具体的程序。通过端口可以锁定计算机上具体的程序&#xff0c;确保程序之间进行沟通。 IP地址相当于小区地址&#xff0c;在小区内可以有许多用户&#xff08;程序&#xff09;&…

植物大战僵尸融合版最新版1.0下载及安装教程

《植物大战僵尸融合版》最新版1.0已经发布&#xff0c;为粉丝们带来了全新的游戏体验。这个版本由B站UP主蓝飘飘fly精心打造&#xff0c;引入了创新的植物融合玩法&#xff0c;让玩家可以享受策略和创意的结合。以下是游戏的详细介绍和安装指南&#xff1a; 游戏特色介绍 全新…

基于深度学习的图像背景剔除

在过去几年的机器学习领域&#xff0c;我一直想打造真正的机器学习产品。 几个月前&#xff0c;在参加了精彩的 Fast.AI 深度学习课程后&#xff0c;似乎一切皆有可能&#xff0c;我有机会&#xff1a;深度学习技术的进步使许多以前不可能实现的事情成为可能&#xff0c;而且开…

Java--继承

1.继承的本质是对某一批类的抽象&#xff0c;从而实现对世界更好的建模 2.extends的意思是“扩展”&#xff0c;子类是父亲的扩展 3.Java中只有单继承&#xff0c;没有多继承 4.继承关系的两个类&#xff0c;一个为子类&#xff08;派生类&#xff09;&#xff0c;一个为父类…

欧科云链大咖对话:Web3原生创新静默期,科技巨头却在两极化发展

出品&#xff5c;OKG Research 作者&#xff5c;Hedy Bi 上周末&#xff0c;欧科云链研究院接受FT中文的邀请&#xff0c;作为圆桌嘉宾参与了由FT中文网与上海交通大学上海高级金融学院联合主办的金融大师课。在圆桌环节&#xff0c;笔者与各位教授和金融行业科技创新前沿实践…

案例精选 | 聚铭网络助力南京市玄武区教育局构建内网日志审计合规体系

南京市玄武区教育局作为江苏省教育领域的先锋机构&#xff0c;其工作重点涵盖了教育政策的实施、教育现代化与信息化的融合、教育资源的优化、教育质量的提升以及教育公平的促进。在这一背景下&#xff0c;网络安全管理成为了确保教育信息化顺利推进的关键环节之一。 根据玄武…

Nacos单机部署、集群部署以及Nacos默认持久化derby数据库和配置mysql数据库

1. Nacos Windows 下载 1.1 去nacos官网下载nacos-server 发布历史 | Nacos 官网https://nacos.io/download/release-history/ 下载版本为 nacos-server-2.3.1.zip 2. Derby数据库 2.1 默认使用Derby数据库 官网下载Derby数据库即可。 Apache Derby数据库https://db.apac…

昇思25天学习打卡营第9天|MindSpore使用静态图加速(基于context的开启方式)

在Graph模式下&#xff0c;Python代码并不是由Python解释器去执行&#xff0c;而是将代码编译成静态计算图&#xff0c;然后执行静态计算图。 在静态图模式下&#xff0c;MindSpore通过源码转换的方式&#xff0c;将Python的源码转换成中间表达IR&#xff08;Intermediate Repr…

VSCode远程服务器

一、安装VSCode Windows安装Visual Studio Code(VS Code)-CSDN博客 二、VSCode中安装Remote-SSH插件 1、在应用商店中搜索Remote - SSH并安装 2、安装后会出现下面标注的图标 三、开始SSH连接 1、点击加号&#xff0c;创建SSH连接 2、输入地址&#xff0c;格式是&#xff1a;…

文件打开的系统错误分析流程

当用户出现“Open file failed”错误时&#xff0c;手动产生dump文件。 &#xff08;1&#xff09;打开资源管理器&#xff0c;选择AppNameXXX.exe进程&#xff0c;右击鼠标选择“创建转储文件” (2) 生成转储文件 3.获取用户转储文件 4.用Visual studio2015打开dump文件分析…

人工智能系列-numpy(三)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 副本和视图 副本 副本是一个数据的完整的拷贝&#xff0c;如果我们对副本进行修改&#xff0c;它不会影响到原始数据&#xff0c;物理内存不再同一位置。副本一般发生在Pytho…

Vue前端打包

关于NGINX 介绍:Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少&#xff0c;并发能力强&#xff0c;在各大型互联网公司都有非常广泛的使用。 NGiMx 官网:https://nginx.org/ conf 配置文件目录 html静态资源文件目录 lo…

html+js+css在线倒计时

代码在图片后面 点赞加关注 谢谢大佬照顾&#x1f61c; 图例 时间到前 时间到后 源代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width,…

10.09面试题目记录

艾融软件 - 线上面试题 排序算法的时间复杂度 O(n^2&#xff09;&#xff1a;冒泡&#xff0c;选择&#xff0c;插入 O(logn&#xff09;&#xff1a;折半插入排序 O(nlogn)&#xff1a;希尔&#xff0c;归并&#xff0c;快速&#xff0c;堆 O(nk)&#xff1a;桶&#xff0c;…