空间数据结构(四叉树,八叉树,BVH树,BSP树,K-d树)

下文参考:https://www.cnblogs.com/KillerAery/p/10878367.html

游戏编程知识课程 - 四分树(quadtree)_哔哩哔哩_bilibili 

利用空间数据结构可以加速计算,是重要的优化思想。空间数据结构常用于场景管理,渲染,物理,游戏逻辑

四叉树 / 八叉树 (Quadtree / Octree )

四叉树索引的基本思想是将地理空间递归划分成不同层次的树结构

可以将已知范围的空间等分成四个相等的子空间,直到树的层次达到一定深度或者满足某种要求

什么是四叉树:

  • 一个四叉树结构是一个存储单元(点,线,或者三角形)
  • 每个节点只能有四个子节点或者没有子节点
  • 每个节点表示了一块区域,他的四个孩子节点表示这个区域的四分
  • 四叉树是二维的概念
  • 每个节点在它们的区域中存储一些objects,有一个最大存储值(对于整颗树来说都是一样的,每个块存储的数量都是根据这个值来调整,如果一个节点存储的值多于最大存储值,就把这个节点四分)
  • 有一个最大深度值(就是树的深度)

怎么把一个物体添加到 Quadtree 里面

当一个quadtree 第一次初始化时,它只有根节点(表现的是整个空间)

从根节点开始,递归执行下面的方法

如果这个节点是叶子节点:

  • 如果递归已经到达最大的深度或者没有达到最大容量,就把这个物体添加到当前节点
  • 否则就把这个区域四分,创建四个子节点,用每个子节点对应一块。然后把这个程序再跑一遍

如果节点不是叶子节点

  • 如果这个物体只是覆盖现在区域的一个四分之一,在这个节点的四分之一子节点上运行这个程序。否则把这个物体加到现在的节点(因为一个点不能同时被不同的节点存储)

怎么去找我们想要的物体

如果给了一个盒子,我们需要去找所有与这个盒子相交的物体

从根节点开始然后递归调用以下方法:

  • 遍历当前节点里面的所有物体,如果与盒子相交,就把这个物体添加到 intersected object list
  • 如果当前节点不是叶子节点:遍历每个孩子节点,如果盒子和这个区域相交,再孩子节点上执行这个方法

如何 remove 物体从 Quadtree

从根节点开始递归调用下面的方法:

如果节点是叶子节点:

  • 如果这个节点有这个物体,就把这个物体移除

如果节点不是叶子节点:

 --  如果这个物体只覆盖当前节点区域的一个四分区域

  • 使用这个四分区域对应的子节点运行这个程序,然后优化一下

--  否则如果这个节点有这个物体就从当前节点移除这个物体

如何去优化节点

如果当前节点的孩子节点不是叶子节点,就 return

计算当前节点以及它的四个孩子节点的所有物体数量,如果小于最大容量,就摧毁掉孩子节点然后将物体都添加到当前节点上

代码来自 chatgpt

using System;
using System.Collections.Generic;// 表示一个矩形区域
public class Rectangle
{public float xMin, xMax, yMin, yMax;public Rectangle(float x, float y, float width, float height){xMin = x;xMax = x + width;yMin = y;yMax = y + height;}// 判断点是否在矩形内部public bool Contains(float x, float y){return x >= xMin && x <= xMax && y >= yMin && y <= yMax;}
}// 表示四叉树节点
public class QuadTreeNode<T>
{public Rectangle boundary; // 节点代表的矩形区域public List<T> objects; // 存储在当前节点中的对象public QuadTreeNode<T>[] children; // 子节点public QuadTreeNode(Rectangle rect){boundary = rect;objects = new List<T>();children = new QuadTreeNode<T>[4];}
}// 四叉树类
public class Quadtree<T>
{private QuadTreeNode<T> root; // 根节点private int maxObjectsPerNode = 10; // 每个节点最多存储的对象数量private int maxLevels = 5; // 最大递归深度public Quadtree(Rectangle bounds){root = new QuadTreeNode<T>(bounds);}// 插入对象public void Insert(T obj, float x, float y){Insert(obj, root, x, y, 0);}// 递归插入对象private void Insert(T obj, QuadTreeNode<T> node, float x, float y, int level){if (node.children[0] != null) // 如果有子节点{int index = GetIndex(node, x, y); // 获取对象应该插入的子节点索引if (index != -1) // 如果对象属于子节点{Insert(obj, node.children[index], x, y, level + 1);return;}}node.objects.Add(obj); // 将对象添加到当前节点if (node.objects.Count > maxObjectsPerNode && level < maxLevels) // 如果当前节点对象数量超过阈值且还可以递归分割{if (node.children[0] == null) // 如果没有子节点,创建子节点{SplitNode(node);}// 将当前节点的对象重新分配到子节点中int i = 0;while (i < node.objects.Count){T item = node.objects[i];int index = GetIndex(node, x, y);if (index != -1){node.objects.RemoveAt(i);node.children[index].objects.Add(item);}else{i++;}}}}// 分割节点private void SplitNode(QuadTreeNode<T> node){float subWidth = node.boundary.xMax - node.boundary.xMin;float subHeight = node.boundary.yMax - node.boundary.yMin;float xMid = node.boundary.xMin + (subWidth / 2);float yMid = node.boundary.yMin + (subHeight / 2);// 创建四个子节点node.children[0] = new QuadTreeNode<T>(new Rectangle(xMid, yMid, subWidth, subHeight));node.children[1] = new QuadTreeNode<T>(new Rectangle(node.boundary.xMin, yMid, subWidth, subHeight));node.children[2] = new QuadTreeNode<T>(new Rectangle(node.boundary.xMin, node.boundary.yMin, subWidth, subHeight));node.children[3] = new QuadTreeNode<T>(new Rectangle(xMid, node.boundary.yMin, subWidth, subHeight));}// 获取对象应该插入的子节点索引private int GetIndex(QuadTreeNode<T> node, float x, float y){int index = -1;float xMid = node.boundary.xMin + (node.boundary.xMax - node.boundary.xMin) / 2;float yMid = node.boundary.yMin + (node.boundary.yMax - node.boundary.yMin) / 2;bool topQuadrant = (y >= yMid);bool bottomQuadrant = (y < yMid);bool leftQuadrant = (x < xMid);bool rightQuadrant = (x >= xMid);if (leftQuadrant){if (topQuadrant){index = 0;}else if (bottomQuadrant){index = 2;}}else if (rightQuadrant){if (topQuadrant){index = 1;}else if (bottomQuadrant){index = 3;}}return index;}// 查询区域内的对象public List<T> QueryRange(Rectangle range){List<T> result = new List<T>();QueryRange(root, range, result);return result;}// 递归查询区域内的对象private void QueryRange(QuadTreeNode<T> node, Rectangle range, List<T> result){if (!node.boundary.Contains(range.xMin, range.yMin) && !node.boundary.Contains(range.xMax, range.yMax)){return;}foreach (T obj in node.objects){if (range.Contains(range.xMin, range.yMin)){result.Add(obj);}}if (node.children[0] != null){foreach (QuadTreeNode<T> child in node.children){QueryRange(child, range, result);}}}
}// 示例使用
class Program
{static void Main(string[] args){Rectangle bounds = new Rectangle(0, 0, 100, 100);Quadtree<int> quadtree = new Quadtree<int>(bounds);// 插入对象quadtree.Insert(1, 10, 10);quadtree.Insert(2, 20, 20);quadtree.Insert(3, 30, 30);quadtree.Insert(4, 40, 40);quadtree.Insert(5, 50, 50);quadtree.Insert(6, 60, 60);quadtree.Insert(7, 70, 70);quadtree.Insert(8, 80, 80);quadtree.Insert(9, 90, 90);quadtree.Insert(10, 100, 100);// 查询区域内的对象Rectangle queryRange = new Rectangle(25, 25, 30, 30);List<int> result = quadtree.QueryRange(queryRange);foreach (int obj in result){Console.WriteLine("对象:" + obj);}}
}

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

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

相关文章

【过度拟合?秒了!】

目录 引言 一、简化模型复杂度 1 .1 特征选择 1.2 降低多项式阶数 1.3 减少神经元数量或层数 二、使用正则化技术 2.1 L1正则化&#xff08;Lasso&#xff09; 工作原理 应用场景 2.2 L2正则化&#xff08;Ridge&#xff09; 2.3 Elastic Net正则化 2.4 代码事例 …

国内如何购买midjourney?midjourney购买教程?midjourney注册方式?

1. Midjourney介绍 Midjourney 是一款备受欢迎的人工智能生成图像工具&#xff0c;它可以通过输入文字描述&#xff0c;自动生成精美的图像。与许多其他图像生成工具不同&#xff0c;Midjourney 不需要安装任何软件&#xff0c;也不受个人电脑性能的限制&#xff0c;因为它运行…

【测试篇】测试眼里的 BUG

文章目录 如何描述一个bug如何定义 bug 的级别BUG 的生命周期跟开发起争执怎么办&#xff08;高频面试题&#xff09; 如何描述一个bug 一个合格的bug描述应该包含以下几个部分&#xff1a; 发现问题的版本问题出现的环境错误重现的步骤预期行为的描述错误行为的描述其他&…

USB-PD

这是目录 写在前面1、概览2、信息2.1 消息结构2.1.1 消息头 3、soft or hard reset1、soft reset2、hard reset 3、TYPE-C相关握手3.1、CC线的状态3.1.1、默认电源值3.2 TYPE-C设备握手协商过程确定握手类型DRP和DRP设备握手 写在前面 1、记录自己的学习PD协议层的文章 1、概…

消息队列经典应用场景

笔者心中,消息队列,缓存,分库分表是高并发解决方案三剑客。 在职业生涯中,笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章,笔者结合自己的真实经历,和大家分享消息队列的七种经典应用场景。 1 异步&解耦 笔者曾经负责某电…

00、SpringBatch 4.x.x版本:简单入门

00、SpringBatch批处理 一、介绍1、什么是批处理&#xff1f;2、官网3、优势4、组织架构5、程序运行架构图 二、入门案例-H2版(内存)1、新建项目2、引入依赖3、新建HelloJob.java 三、入门案例-MySQL版1、引入依赖2、修改 application.yml3、验证 四、案例解析1、EnableBatchPr…

国产桌面操作系统统一身份认证及2FA双因子认证安全升级方案

某金融运营服务公司&#xff0c;主要负责业务处理、客户服务、业务监控、报表统计等金融运营服务&#xff0c;为集团下设二级单位&#xff0c;坐落于一线城市&#xff0c;对政策风向有很高的敏锐度。 该公司已为公司业务人员、客户服务、监督员等配备了数百台国产桌面操作系统…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单图像浮雕效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单图像浮雕效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单实战案例 之七 简单图像浮雕效果 一、简单介绍 二、简单图像浮雕效果实现原理 三、简单图像浮雕效果案例实现简单步骤 四、注…

网络七层模型之会话层:理解网络通信的架构(五)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【豫都故郡·领航新篇】Springer独立出版 |第二届先进无人飞行系统国际会议(ICAUAS 2024)

会议简介 Brief Introduction 2024年第二届先进无人飞行系统国际会议(ICAUAS 2024) 会议时间&#xff1a;2024年6月14日-16日 召开地点&#xff1a;中国南昌 大会官网&#xff1a;ICAUAS 2024-2024 2nd International Conference on Advanced Unmanned Aerial Systems2024 2nd …

【C++】力扣-415-字符串相加(双指针,图例详解!!!)

目录 一、前言 二、字符串相加 三、共勉 一、前言 最近春招已经开始&#xff0c;看周围的同学都在投递一些大厂的实习&#xff0c;某为的手撕代码 --- 字符串相乘&#xff0c;某讯的手撕代码 --- 字符串相减等。 于是专门去 Leetcode 上搜索了一下&#xff0c;发现这类题目是面…

conda使用记录

linux 使用conda创建新一个新的python环境过程 conda create -n recommendation_env python3.8.18 # 指定python版本 conda env list # 查看所有的环境 conda activate recommendation_env # 激活创建的新环境 pip install flask # 安装依赖 或者 pip install flask版本号 或者…

脑机交互,屏幕是必须?No!让机器人发出激光光点实现脑机接口交互

一般说来&#xff0c;传统脑机接口(BCI)系统的交互过程依靠一个图形化的用户界面&#xff0c;不利于设备的便携性。而一种无屏幕的BCI可以通过让机器人在外界环境中发出刺激从而实现更直接的命令其中机器人使用激光光点凸显环境中的候选对象&#xff0c;而用户的目标则从脑电图…

跳跃游戏-java

题目描述: 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 解题思想: …

AIGC新潮流!手势灵动数字人视频、百变模特服装图、3D模型纹理一键生成

1、营销应用:AI生成生成带手势(手部动作)的数字人视频 (1)一个基于扩散模型的数字人生成框架,专注于生成具有全身动作的主播风格视频。该系统通过仅需一分钟的个人视频片段进行训练,便能自动生成具有精确躯干和手部动作的主播风格视频。 (2)定位:该框架定位于解决现…

docker环境配置过程中的常见问题

1、pull镜像问题 docker pull jenkins/jenkins:lts Using default tag: latest Trying to pull repository docker.io/library/centos ... Get https://registry-1.docker.io/v2/library/centos/manifests/latest: Get https://auth.docker.io/token?scoperepository%3Alibr…

自动驾驶-如何进行多传感器的融合

自动驾驶-如何进行多传感器的融合 附赠自动驾驶学习资料和量产经验&#xff1a;链接 引言 自动驾驶中主要使用的感知传感器是摄像头和激光雷达&#xff0c;这两种模态的数据都可以进行目标检测和语义分割并用于自动驾驶中&#xff0c;但是如果只使用单一的传感器进行上述工作…

数据处理库Pandas数据结构DataFrame

Dataframe是一种二维数据结构&#xff0c;数据以表格形式&#xff08;与Excel类似&#xff09;存储&#xff0c;有对应的行和列&#xff0c;如图3-3所示。它的每列可以是不同的值类型&#xff08;不像 ndarray 只能有一个 dtype&#xff09;。基本上可以把 DataFrame 看成是共享…

【机器学习之---数学】熵和交叉熵

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 熵和交叉熵 1. 熵 概率分布的熵可以被解释为与给定分布中的随机变量相关的不确定性或缺乏可预测性的度量。 我们还可以使用熵来定义数据源的信息内容。…

小程序UI设计规范,界面设计尺寸详解

作为互联网技术的重要组成部分&#xff0c;小程序在日常生活中发挥着越来越重要的作用。因此&#xff0c;了解和严格遵守小程序的 UI 设计标准非常重要&#xff0c;它不仅可以帮助我们在保证良好用户体验的同时优化小程序&#xff0c;还可以使我们的产品在竞争激烈的市场中占据…