范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

快速检索碰撞图形四叉树碰撞检测

  大家好,我是前端西瓜哥。
  在上篇文章我们讨论了使用  脏矩形渲染 ,通过重渲染局部的图形来提优化 Canvas 的性能,将 GPU 密集转换为 CPU 密集。 看这篇文章
  《Canvas 性能优化:脏矩形渲染》
  CPU 密集在哪?
  在需要遍历 所有的图形,判断它们是否和脏矩形发生相交(碰撞),保存发生碰抓给你的图形,将它们在局部进行重绘。
  有没有办法减少需要遍历的图形,不要遍历全部的图形,而是少量的图形呢?有一个办法是使用 四叉树。四叉树碰撞检测原理我们将区域的分割表述为 "节点",因为是四叉树;
  将画布上的真实图形就叫做 "图形"。
  四叉树本质使用了 空间分割,给图形加 索引,将视口界面分割成多个区域,每个区域记住自己包含了哪些图形。
  然后移动目标图形时,判断它落在哪个区域,取出所在区域的图形,这些图形集合就是和目标图形发生碰撞图形的超集。
  这些区域外的图形就被我们排除了。
  算法实现的要点:
  创建根节点,根节点保存区域的信息 x、y、width 和 height。
  添加图形时,当一个节点内的节点数量大于阀值,就将整个区域均等切割为 4 等份的子节点,将图形从当前区域取出,重新放入到这些子节点内,从而将节点的归属划分为更小的区域。
  (原来的区域转换为索引层,真正保存节点的地方放到了它的子区域上)
  当我们提供一个碰撞矩形,我们从四叉树顶节点往下找,看是否有子节点。如果有,使用矩形碰撞算法找出它所在的子节点有哪些(可能有多个)。对这些子节点重复前面的操作,进行递归,找到所有的图形。
  这些图形就是碰撞矩形可能相交的矩形,但相对所有图形,又不至于太多。四叉树碰撞检测算法
  先看看经典算法实现。
  算法我就不自己实现了,这里展示 quadtree-js 库的代码实现。
  构造函数:function Quadtree(bounds, max_objects, max_levels, level) {   this.max_objects = max_objects || 10; // 节点内最大对象数量   this.max_levels = max_levels || 4; // 树的最大深度   this.level = level || 0;   this.bounds = bounds; // 区域,结构为 {x, y, width, height}   this.objects = []; // 保存图形的地方   this.nodes = []; // 4 个子节点,到达阀值时才创建 }
  这是一个内部私有方法,当节点内图形过多,超过阀值,就将当前节点分裂成 4 个子节点:// 切割:生成 4 个子节点 Quadtree.prototype.split = function () {   var nextLevel = this.level + 1,     subWidth = this.bounds.width / 2,     subHeight = this.bounds.height / 2,     x = this.bounds.x,     y = this.bounds.y;   // 右上   this.nodes[0] = new Quadtree(     {       x: x + subWidth,       y: y,       width: subWidth,       height: subHeight,     },     this.max_objects,     this.max_levels,     nextLevel   );   // 左上   this.nodes[1] = new Quadtree(     {       x: x,       y: y,       width: subWidth,       height: subHeight,     },     this.max_objects,     this.max_levels,     nextLevel   );   // 左下   this.nodes[2] = new Quadtree(     {       x: x,       y: y + subHeight,       width: subWidth,       height: subHeight,     },     this.max_objects,     this.max_levels,     nextLevel   );   // 右下   this.nodes[3] = new Quadtree(     {       x: x + subWidth,       y: y + subHeight,       width: subWidth,       height: subHeight,     },     this.max_objects,     this.max_levels,     nextLevel   ); };
  计算某个图形落在当前节点的哪个子节点,拿到对应节点索引值数组:// 找到某个 box 落在在哪个区域 Quadtree.prototype.getIndex = function (pRect) {   var indexes = [],     verticalMidpoint = this.bounds.x + this.bounds.width / 2,     horizontalMidpoint = this.bounds.y + this.bounds.height / 2;   var startIsNorth = pRect.y < horizontalMidpoint,     startIsWest = pRect.x < verticalMidpoint,     endIsEast = pRect.x + pRect.width > verticalMidpoint,     endIsSouth = pRect.y + pRect.height > horizontalMidpoint;   // top-right quad   if (startIsNorth && endIsEast) {     indexes.push(0);   }   // top-left quad   if (startIsWest && startIsNorth) {     indexes.push(1);   }   // bottom-left quad   if (startIsWest && endIsSouth) {     indexes.push(2);   }   // bottom-right quad   if (endIsEast && endIsSouth) {     indexes.push(3);   }   return indexes; };
  插入一个图形,先看是否存在子节点,有的话说明当前节点变成了索引层,通过矩形碰撞算法找到所在的子节点,对这些子节点做插入操作:Quadtree.prototype.insert = function (pRect) {   var i = 0,     indexes;   // 存在子节点,则插入到子节点   if (this.nodes.length) {      indexes = this.getIndex(pRect); // 找到索引位置     for (i = 0; i < indexes.length; i++) {       this.nodes[indexes[i]].insert(pRect); // 递归 insert     }     return;   }   // 没有子节点,不是索引层,图形放到前节点下   // (有个小 BUG,就是不在范围内的图形也加上去了)   this.objects.push(pRect);   // 如果对象太多,构建子节点   if (     this.objects.length > this.max_objects &&     this.level < this.max_levels   ) {     if (!this.nodes.length) {       this.split();     }     // 将 objects 取出,放入这些子节点中     for (i = 0; i < this.objects.length; i++) {       indexes = this.getIndex(this.objects[i]);       for (var k = 0; k < indexes.length; k++) {         this.nodes[indexes[k]].insert(this.objects[i]);       }     }     this.objects = [];   } };
  返回目标图形所在节点下的所有图形:// 传入一个矩形,取出它所在节点的所有矩形 // 这个方法能返回 Quadtree.prototype.retrieve = function (pRect) {   // 提取目标矩形所在区间下的所有矩形   var indexes = this.getIndex(pRect),     returnObjects = this.objects;   // 可能需要递归。   //if we have subnodes, retrieve their objects   if (this.nodes.length) {     for (var i = 0; i < indexes.length; i++) {       returnObjects = returnObjects.concat(         this.nodes[indexes[i]].retrieve(pRect)       );     }   }   // 移除重复的节点   returnObjects = returnObjects.filter(function (item, index) {     return returnObjects.indexOf(item) >= index;   });   return returnObjects; };
  非常简单,一些可以改善的能力。没有添加映射功能 ,最后返回的图形都是 box 对象信息,我们可以考虑改造为 insert(rect, data)  ,保存额外的信息,比如实际形状。动态收缩 :移除某个图形后更新树结构,并在发现图形数量低于阀值时,取出图形放到父节点上,销毁子节点;修改根节点范围  后,需要重置整棵树,如何高效重置等;四叉树的图形类型 ,常见的是矩形,但还可以是点、直线、曲线等,如果需要可以考虑支持。
  请根据实际需要进行扩展。一些权衡
  处于节点内分割线上的图形,它是归属于多个子节点的,所以最终会同时放到它的多个子节点下,会花费内存。
  极端情况下,一个非常大的图形,会保存在所有的节点下。
  如果想节省内存,可以直接保存到当前节点上,不放到子节点上,可以减少内存使用,只是最后返回的被碰撞图形会多一点。因为图形可能只压在了两个子节点的交界线上,比如 A、 B ,但目标矩形是在其他的子节点 C 上,但因为它们来自同一个父节点,所以拿到了这个不可能在 C 的图形。
  后者会更好一些,但如果一个图形刚好在画布中心,那每次取出的碰撞图形都会有它(这点可以通过松散四叉树解决)。松散四叉树
  经典四叉树有个问题,就是如果图形的物理信息是比较动态的,当总是在边界附近时,就会发生频繁地将图形从一个节点取出并放到另个节点下。
  对此我们可以额外设置一个出口边界。这个出口边界要比入口边界要大,只有当图形离开这个出口边界,才会更新提取图形到新的节点。
  这样,当图形划分到另一个节点上时,就 需要移动较长的距离才能回到原来节点下,轻微地移动不会导致剧烈的更新。
  通常出口边界边长为入口边界的两倍最佳,为什么不知道,经验之谈。
  其他空间分割思想的算法
  简单介绍一些也使用了 空间分割 思想的算法。跳表 :一种有序链表,通过叠加大量的索引层,可以进行链表形式的 "二分查找",达到高效的 O(logn)   时间复杂度,但也带来了内存的消耗。Redis 中的有序集合(Sorted Set)底层使用了跳表,一个原因是可以高效地获取区间内的数据集;B+ 树 :一种平衡二叉树,有点像跳表,但树的层数最多为三层,MySQL 的索引实现使用了 B+ 树,因为层数较少,可以减少 IO 操作;R 树 :R 表示矩形的意思。相比前面两种单维的范围查找,R 树能做高效的高维查找。比如地图中,我们可以通过 R 树将 距离 相近的高维图形合并为一个大节点,当搜索 "2km 内的药店" 时,如果你落到某个大节点上,我们只要遍历一个大节点下的所有节点,而不是要遍历整个市。
  R 树的思路是最接近四叉树的,它其实是另一种 减少图形遍历的方案,可以适用于高效剔除视口范围之外的图形。
  R 树有个 star 数很多的库,叫做 RBush,感兴趣可以看看。结尾
  我是前端西瓜哥,欢迎关注我,学习更多前端知识。

情绪文案当初惊艳,只因为少见多怪游戏新春创作纪日子,过的是心情生活,要的是质量。人是一种会自己骗自己的动物。我们吃了很多无益的苦,虚掷了不少年华。事实是,当你犹豫要不要去做一件事的时候,其实你内心已经有了选择,只无名的程耳美学各路女明星,周迅江疏影张婧仪哪个惊艳你了春节档无名火热上映中,程耳导演的美学,之前在罗曼蒂克消亡史中就领略到了。这次无名也依旧出色。除了电影整体氛围感极强,几位主演表现出彩以外,几个女明星也是电影中很亮眼的存在1江疏影江郭晓婷登男人装太惊艳!清纯脸欧美身材,湿发配裙装风情满满女性的可塑性是非常高的,有些是对于年轻女性而言,不仅可以驾驭各种时尚风格,甚至还能释放出不同的魅力,可性感可优雅可端庄也可甜美,不同的穿衣风格自然就可以体现出别样的美。对于三十岁左分享一款质朴优雅的棒针开衫,简洁大方的针织样式,版型经典十足棒针毛衣不一定针织(花样)独特越好看,有时候,编织(样式)简洁质朴也许会更经典耐看哦!这款编织(样式)经典又百搭的羊毛针织开衫,就十分的质朴优雅。中长显瘦的(版型)简单又显气质,针是巧合,还是有意?兵团新城白杨市原本与歌曲小白杨同名2023年1月20日,新疆生产建设兵团第九师的城市白杨市,正式被国务院批准成立。这个十年磨一剑才诞生出来的市,或者说千呼万唤始出来的城市,原本最早取得名字和军旅歌曲小白杨以及小白杨动作游戏中国功夫味更足师父在下次更新中将加入粤语配音开发商Sloclap已经证实,旗下广受好评的武术动作游戏师父(Sifu)将在下次更新中加入粤语配音。早在12月,开发者就宣布游戏将获得新的竞技场模式,该模式将包含在2023年3月发喜欢一个人是有能量条的无论什么时候想要彻底地放下一个人或一件事。过程中是十分艰难的。就好比还在幼苗时期的树木被嵌进去一枚钉子。待到它枝繁叶茂时。那颗钉子留下的痕迹依然存在。人们常说,时间会抚平一切。但其英雄联盟无限火力最恶心的5大英雄,有你觉得比这更恶心的吗?Top5。巨魔之王玩过无限火力的都知道,巨魔的恶心并不在于对线,而是他的拆塔速度极快,单挑能力极强,只要前期有点小优势,后期直接化身拆迁办,就只管偷你家,拦都拦不住,疯狂挑衅对面的2023年退休养老金继续提高,5000元以下的老人能否涨500元?进入2023年以后,很多老人关注的就是养老金继续调整的问题了。截止目前,已经有河北河南四川上海北京等多个省份,通过政府工作报告财政预算或者办实施方案等方式,明确继续调整退休人员基本公共节假日最多的国家是哪些,它们一年有多少公共节假日?正值全国人民欢度新春佳节,让我们来了解一下其它国家的节假日情况。公共节假日可以给他们带来民族自豪感,也提供了一个表达感谢和纪念国家历史上重大事件的机会。这些日子通常包括特殊的仪式或狂飙孟德海或许是隐藏的幕后人物之一头条创作挑战赛狂飙现在已经更新到第21集,除了已经浮出水面的赵立东以外,其他幕后人物,有的已经开始逐渐露出冰山一角。徐江死后,孟德海调任青华区担任青华区书记,这个时候的区长正是第一
小米13Lite配置曝光!起售价仅4000元或3月8日开启预定手机中国新闻此前不久,小米在国内推出了全新旗舰机型小米13系列。该系列新机在上市后,受到了一系列的好评,甚至一度供不应求。而在小米13系列发布后不久,便有消息称小米13系列将在全球1岁幼儿生命通道先天受阻,专家妙手修缺补瘘重建食管郴州市第一人民医院郴州头条小沫今年1岁,平时经常咳嗽,主要表现为轻咳乏力上呼吸道感染肺炎等症状。小沫妈妈想找到孩子反复咳嗽的原因,于是在郴州市第一人民医院北院(郴州市儿童医院)儿童国安进行海口集训首堂训练课李可以试训身份参加北京时间2月9日上午,赶赴海口集训的北京国安在主帅斯坦利门佐与球队会合后进行了第一堂训练课,入籍球员李可以试训球员身份参加了训练。据北京国安官方消息消息,为备战新赛季中超联赛,国安慈禧第一次见到电灯泡时,随口说出了一句话,体现了她的封建愚昧在阅读此文前,诚邀您点击一下关注,既方便您进行讨论与分享,又可以让您下次继续阅读相关文章,带来不一样的参与感,感谢您的支持。电灯,作为我们现在常用的照明工具,大家对它都不陌生,可大慈禧死后李莲英还活了3年,没了主子,他过得怎么样呢?慈禧死后,裕隆太后为表彰他为皇家服务多年,特准许赐他原品休致头衔。这原品休致的意思很简单,就相当于退休后还享受和在职时一样的薪资待遇。这在整个大清的太监里是绝无仅有的。让人意外的是男人到了60岁还能喝酒吗?专家建议3件事不要做,也能放心喝最近几天,关于退休的话题可谓是备受关注,听说以后退休年龄延到了65岁。其实不管怎么改,在老一辈人心里,60岁才是真正的人生分界线,是中年到老年的过渡,进入这个阶段,人们的心态和身体为何三朝老臣张廷玉在最后却被乾隆抄家当年雍正遗诏一出的时候,张廷玉就知道接下来的日子不妙了,因为雍正太给他面子了,已经触犯了大清皇帝那高度集中的君权底线。看到雍正遗诏的时候,乾隆除了恭恭敬敬地接旨以外,脸肯定是黑的。1971年美日图谋钓鱼岛,一华裔老太反对岛是我的,我有慈禧手谕1972年2月,越南西贡的成功日报上发表了一篇社论,两天之后的香港新闻天地周刊上也发表了一篇文章。这两个文章都在叙述一件事,那就是美国为了名正言顺地把钓鱼岛划分给日本,在1971年隐姓埋名于甘肃!它是中国最神秘城市,代号404提起404你会想到什么?是所请求的页面不存在?是已被删除?还是无法访问?在国内有这么一个地方,地图上没有它的名字,没有邮政编码,没有电话区号,甚至连GPS都无法达到。能证明它存在的满足个性化需求,带来更舒心体验清晨,AI助手被语音唤醒后播放几首悦耳的歌曲黄昏,在下班路上打开扫地机器人的控制程序,回家后地面早已被打扫干净如今,远程监控智能交互等新功能在家居产品中逐渐普及,智能家居产品成了人春运写真丨雅西高速的守护者春运写真原标题雅西高速的守护者工人日报中工网记者北梦原通讯员王冰大年初二一大早,四川省交通执法总队第五支队六大队负责人刘勇,就带着队员们驾车上路勘察路面,关注沿途气温变化检查路面积