Hilbert编码 思路和scala 代码

news2024/11/24 14:14:29

需求:

使用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 //x
    val lon_half = (bounds._1.lon + bounds._2.lon) / 2 //y


    // 反转差值
    val lat_reverse = point.lat - lat_half
    val 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.getTileCode

object 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 //x
    val 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_half
    val 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)/2
    val 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))
    // 右上角  42
    val p14 = Point(18.75, 18.75)
    val p24 = Point(20, 20)
    val maxLevel4 = 4
    val tileCode14 = getTileCode(p14, p24, bounds, maxLevel4)
    println(s"Tile Code for given region: $tileCode14")

    // 左上角 //21
    val 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")


    //   5
    val 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 Error
    val 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
    // 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")



    // 34
    val p1 = Point(16.25, 16.25)
    val p2 = Point(17.5, 17.5)
    val maxLevel = 3
    val tileCode = getTileCode(p1, p2, bounds, maxLevel4)
    println(s"Tile Code for given region: $tileCode")

    // 10
    val 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")

    // 8
    val 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")

    // 32
    val 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.coloradmin.cn/o/1898434.html

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

相关文章

【重磅】万能模型-直接能换迪丽热巴的模型

万能模型&#xff0c;顾名思义&#xff0c;不用重新训练src&#xff0c;直接可以用的模型&#xff0c;适应大部分原视频脸 模型用法和正常模型一样&#xff0c;但可以跳过训练阶段&#xff01;直接到合成阶段使用该模型 本模型没有做Xseg&#xff0c;对遮挡过多的画面不会自动适…

掌握 Postman 脚本:入门指南

在探索 API 测试自动化环墁下&#xff0c;Postman 脚本显现其强大功能和灵活性&#xff0c;它不仅仅是 API 测试的工具&#xff0c;更是一个综合性的自动化平台。 Postman 脚本简介 Postman 允许用户在 API 请求生命周期中运行 JavaScript 脚本&#xff0c;这些脚本分为以下三…

FineBI在线学习资源-数据处理

FineBI在线学习资源汇总&#xff1a; 学习资源 视频课程 帮助文档 问答 数据处理学习文档&#xff1a; 相关资料&#xff1a; 故事背景概述-https://help.fanruan.com/finebi6.0/doc-view-1789.html 基础表处理-https://help.fanruan.com/finebi6.0/doc-view-1791.html …

联合概率密度函数

目录 1. 什么是概率密度由联合概率密度求概率参考链接 1. 什么是概率密度 概率密度到底在表达什么&#xff1f; 外卖在20-40分钟内送达的概率 随机变量落在[20,40]之间的概率。下图中&#xff0c;对总面积做规范化处理&#xff0c;令总面积1&#xff0c; f ( x ) f(x) f(x)则成…

使用中国大陆镜像源安装最新版的 docker Deamon

在一个智算项目交付过程中&#xff0c;出现了新建集群中的全部 docker server V19 进程消失、仅剩 docker server 的 unix-socket 存活的现象。 为了验证是否是BD产品研发提供的产品deploy语句缺陷&#xff0c;需要在本地环境上部署一个简单的 docker Deamon 环境。尴尬的是&a…

SD16S1Y 符合GB2312标准16X16点阵汉字库芯片IC

一般概述 SD16S1Y是一款内含16x16点阵的汉字库芯片&#xff0c;支持GB2312国标简体汉字(含有国家信标委 合法授权)、ASCII字符。排列格式为竖置横排。用户通过字符内码&#xff0c;利用本手册提供的方法计算出 该字符点阵在芯片中的地址&#xff0c;可从该地址连续读出字…

【JavaWeb程序设计】JSP编程

目录 一、编写JSP页面&#xff0c;在界面上显示1-9&#xff0c;9个链接&#xff0c;单击每个链接&#xff0c;能够在另一个页面打印该数字的平方。 1. 运行截图 2. 第一个jsp页面&#xff08;index.jsp&#xff09; 3. 第二个jsp页面&#xff08;square.jsp&#xff09; 二…

信创-办公软件应用工程师认证

随着国家对信息技术自主创新的战略重视程度不断提升&#xff0c;信创产业迎来前所未有的发展机遇。未来几年内&#xff0c;信创产业将呈现市场规模扩大、技术创新加速、产业链完善和国产化替代加速的趋势。信创人才培养对于推动产业发展具有重要意义。应加强高校教育、建立人才…

卫星网络——Walker星座简单介绍

一、星座构型介绍 近年来&#xff0c;随着卫星应用领的不断拓展&#xff0c;许多任务已经无法单纯依靠单颗卫星来完成。与单个卫星相比&#xff0c;卫星星座的覆盖范围显著增加&#xff0c;合理的星座构型可以使其达到全球连续覆盖或全球多重连续覆盖&#xff0c;这样的特性使得…

SpringBoot的在线教育平台-计算机毕业设计源码68562

摘要 在数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;在线教育已成为教育领域的重要趋势。为了满足广大学习者对于灵活、高效学习方式的需求&#xff0c;基于Spring Boot的在线教育平台应运而生。Spring Boot以其快速开发、简便部署以及良好的可扩展性&#xff0c…

CVPR2024自动驾驶轨迹预测方向的论文整理

2024年自动驾驶轨迹预测方向的论文汇总 1、Producing and Leveraging Online Map Uncertainty in Trajectory Prediction 论文地址&#xff1a;https://arxiv.org/pdf/2403.16439 提出针对在线地图不确定性带给轨迹预测的影响对应的解决方案。 在轨迹预测中&#xff0c;利用在…

Linux系统的基础知识和常用命令

1、什么是Linux&#xff1f; 是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹于1991年10月5日首次发布&#xff0c;它主要受到Minix和Unix思想的启发&#xff0c;是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行…

基于Springboot的智慧信息化机房管理系统

1 项目介绍 1.1 研究目的和意义 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对高校共享机房管理方面的要求也在不断提高&#xff0c;需要高校共享机房的人数更是不断增加&#xff0c;使得高校共享机房管理…

【Linux进阶】磁盘分区3——目录树,挂载

Linux安装模式下&#xff0c;磁盘分区的选择&#xff08;极重要&#xff09; 在Windows 系统重新安装之前&#xff0c;你可能会事先考虑&#xff0c;到底系统盘C盘要有多大容量&#xff1f;而数据盘D盘又要给多大容量等&#xff0c;然后实际安装的时候&#xff0c;你会发现其实…

【系统架构设计师】计算机组成与体系结构 ⑩ ( 磁盘管理 | 磁盘移臂调度算法 | 先来先服务算法 | 最短寻道时间优先 | 扫描算法 | 循环扫描算法 )

文章目录 一、磁盘移臂调度算法1、磁盘移臂调度算法简介2、先来先服务算法3、最短寻道时间优先4、扫描算法5、循环扫描算法 二、最短寻道时间优先算法示例 一、磁盘移臂调度算法 1、磁盘移臂调度算法简介 磁盘 数据块读取 的 性能 主要由 寻道时间旋转延时 决定 ; 旋转延时 …

软设之UML图中的用例图

UML图中用例图 用例图描述一组用例&#xff0c;参与者及它们之间的关系 关系包括&#xff1a; 包含关系&#xff0c;扩展关系&#xff0c;泛化关系 用例建模的流程&#xff1a; 识别参与者 合并需求获得用例 细化用例描述 调整用例模型

《C语言》认识数据类型和理解变量

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;C语言基础 目录 前言 一、数据类型的介绍 1.1 字符型 1.2 整形 1.3 浮点型 1.4 布尔类型 1.5 各种数据类型的长度 1.5.1 sizeof操作符 1.5.2 数据类型长度…

【React Hooks原理 - useCallback、useMemo】

介绍 在实际项目中&#xff0c;useCallback、useMemo这两个Hooks想必会很常见&#xff0c;可能我们会处于性能考虑避免组件重复刷新而使用类似useCallback、useMemo来进行缓存。接下来我们会从源码和使用的角度来聊聊这两个hooks。【源码地址】 为什么要有这两个Hooks 在开始…

2.4章节python中字符串类型

在Python中&#xff0c;字符串&#xff08;String&#xff09;是一种基本的数据类型&#xff0c;用于表示文本信息。字符串可以包含字母、数字、标点符号或任何Unicode字符。Python中的字符串是不可变的&#xff0c;这意味着一旦创建了字符串&#xff0c;就不能更改字符串中的字…

无人机运营合格证及无人机驾驶员合格证(AOPA)技术详解

无人机运营合格证及无人机驾驶员合格证&#xff08;AOPA&#xff09;技术详解如下&#xff1a; 一、无人机运营合格证 无人机运营合格证是无人机运营企业或个人必须获得的证书&#xff0c;以确保无人机在运营过程中符合相关法规和标准。对于无人机运营合格证的具体要求和申请…