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

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

  大家好,我是前端西瓜哥。
  在上篇文章我们讨论了使用  脏矩形渲染 ,通过重渲染局部的图形来提优化 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,感兴趣可以看看。结尾
  我是前端西瓜哥,欢迎关注我,学习更多前端知识。

(体育)短道速滑世界杯蒙特利尔站收官张楚桐获女子1000米第五名新华社北京10月31日电(记者丁文娴李嘉)国际滑冰联合会官网消息,20222023赛季短道速滑世界杯加拿大蒙特利尔站当地时间30日决出六项冠军,张楚桐获得女子1000米第二次比赛第骑士5连胜!米切尔再砍38分,乐福8记三分,落选秀大爆发北京时间10月31日,NBA常规赛继续鏖战,骑士队主场迎战尼克斯。这算得上是一场强强对话,两队赛前战绩都是东部前五,阵容年轻冲击力强,但尼克斯缺少真正的巨星,骑士队现在则拥有米切尔活塞状元兑现天赋带队屠勇士终结5连败10月31日讯卫冕冠军勇士今日客赴底特律汽车城挑战活塞,勇士最近状态不算太好,反观活塞遭遇5连败,急需一场胜利来止住颓势。第一节双方你来我往始终没有拉开分差,活塞稍微落后第一节,活他在申花连替补席都坐不上,如今却成谢晖爱将,本轮为大连献绝杀日前,大连队在本轮中超跟武汉长江队狭路相逢,这场比赛经过90分钟的激战,最终以球队2比1获胜。大连队能拿三分的最大功臣,就是中场核心费煜。武汉长江队虽然在之前的比赛中连战连败,但是记者欧洲最高法院可能批准欧超,这使得张康阳放弃出售国米直播吧10月31日讯据意大利足球记者马尔科巴尔扎吉透露,张康阳之所以改变出售国米的想法,是因为看到了欧超联赛的曙光。此前有传闻称,由于财务危机张康阳主席有意出售国米俱乐部,但上周张全球首款!华为MateXs2升级支持北斗卫星消息封面新闻记者孟梅易弋力10月31日,华为宣布折叠旗舰华为MateXs2升级支持北斗卫星消息。这意味着,华为MateXs2将成为全球首款支持北斗卫星消息的折叠屏手机。华为MateXs是个狠人,iPhone12ProMax降价3800元,清仓力度很大因为性能和流畅度上的品质更好,所以一款iPhone的使用时间要比安卓多出好几年,也正是因为如此,苹果手机的用户换机周期一般至少是23年,这和很多一年一换的安卓用户完全不一样。其实你新能源多出力要靠几家抬近日,甘肃新能源日发电量首次突破3亿千瓦时,占当日甘肃全网总发电量的53。09,创历史新高。专家预计,今年西北电网新能源总装机将超火电,成为该区域第一大电源,西北电网也将由此成为全小米12Pro天玑版大跳水1000元,相比于便宜200的一加cepro如何?目前双十一,小米12Pro天玑9000版本的价格12256GB降到了3199元,比一加AcePro的价格贵了200元,但综合硬件素质确实更强一些1天玑9000plus芯片算是和骁龙进博朋友圈这家企业的二尖瓣生物瓣膜将迎来中国首秀爱德华生命科学2021年的展台。受访者供图随着第五届中国国际进口博览会进入倒计时,大量全球首发亚洲首展中国首秀的新品等待着进博会上的集中亮相。作为全球结构性心脏病重症监护以及手术监2022年第43周乘用车板块长城汽车一枝独秀华晨中国收敛锋芒第43周,乘用车板块股价平均下跌8。5,跌幅为五大板块之首,市值合计蒸发2841亿元,其中仅长城汽车双股翻红。具体来看,长城汽车H股和A股逆势上涨10。85和10。16,成为板块耀
新天龙八部老玩家分享唐门核心玩法唐门真是变态首先,唐门技能全面,大部分实用,唐门成长比较高。唐门血脉增长在远攻排名第二,仅次于,与明教天山一脉。唐门内功增幅仅次于武当慕容(别扯天山),唐门属性系数增加杜宣双1。3,也是双属性关于水痘的冷知识,家长不得不看!(通俗易懂)我的孩子在家里什么病都没有,到了学校后,各种病都出来了,而且一时半会还好不。第一次做孩子家长,我们对很多事情都不是特别清楚,遇到孩子生病会显得手足无措。提早了解,提前预防,比生了病孩子长高全靠吃?奶奶每次喂得都很饱,孙子却比同龄娃矮了一个头孩子长高这样吃育儿事务所表妹前年生了一个大胖小子,生下来体重7。8斤(3。9kg),身高56CM,取名润润。因为表妹要上班,小润润两个多月时,就被表妹交给了婆婆带。起初,表妹下班回秋季补钙怎样吃,给孩子做这些菜肴,含钙高,孩子长高,家长高兴本期导读秋季补钙怎样吃,常给孩子做这些菜肴,含钙高,孩子长高,家长高兴进入秋季了,天气渐渐地凉爽起来,人的胃口也变得好了起来。很多家长都为孩子长个的问题犯愁。你知道吗?孩子秋季补钙怎样培养自信心,家长朋友们一定要收藏人需要自信,人要自信就不要去比较,只要一比较能量就下降,怎么比较人都有劣势的。有的人长得好看,有人长得一般,有人长得高,有人长的矮,有人家庭背景好,有的人没有任何家庭帮助,只要进入出现围产期抑郁,孕产妇该如何进行调节?本期专家张玲首都医科大学附属北京安定医院抑郁症治疗中心大科主任有人说怀孕是美好的体验,也有人说是种甜蜜的负担,除了身体的变化,孕产妇心理状态改变也是不容忽视的。孕后脾气暴躁紧张焦虑你都不看书,孩子怎么会看?如果你做不到,请找个环境影响他按约定的时间,带娃来诊所复诊(牙齿正畸)。一对父女倚靠在沙发一角,两人一起读绘本,爸爸声音不大,读得绘声绘色,女儿认真看着,听得津津有味,多么美好的画面。这是一间书香气十足的私人诊宝宝在幼儿园应该学认字吗?上一年级才明白,提前做好准备很重要邻居宝妈以前经常说,自己家的宝宝不需要那么累,应该有一个无忧无虑的童年,上小学之前就让孩子快乐地玩耍就可以了。宝宝在幼儿园阶段大多数的时间都在玩,邻居家长认为幼儿园把字都学完了,上山西这座古镇竟藏着一座老供销社,已有70年了,至今还保持着原貌提起供销社,估计很多习惯了网购的90后小伙伴都会一脸茫然。然而,在计划经济时代,人们购物的主要场所就是供销社,尤其是过去的农村,供销社商店就如同村子里的百货大楼,农药化肥镰刀斧头布哈哈两天没更新视频,原因找到了吗熟悉哈哈的粉丝们都知道,哈哈在旅行的视频,每天都在早晨的七点准时更新,最近连续两天哈哈都没有更新视频了,粉丝们急得像热锅上的蚂蚁。毫无疑问哈哈肯定发生了什么事?那到底是发生了什么呢三星预告终极SSD升级PCIe5。0的990Pro要来了近日,三星半导体官方在社交媒体发布预热消息,宣布终极SSD已经在路上了,并放出了产品的剪影图片。从产品剪影,以及近一段时间三星的产品节奏来看,这款被称为终极SSD的新品,很可能是已黄芪泡水喝?太浪费了!想要气血双补,中医教你一招作用翻倍大家好,我是崔医生很多人呢,感觉身体啊,特别虚弱,特别没劲,就特别喜欢去用黄芪,那黄芪呢,它本身有非常好的去补肺脾之气的作用,它呢补气升阳,益卫固表,对于呢有气虚的这样的问题啊,在无糖低糖饮品1水确保你每天摄入推荐的水总是很重要,而你应该得到适当量的无穷无尽的原因清单会变得更长。水总是会成为最好的饮料建议,糖尿病也不例外,保持水分的头等大事,也是希望增加液体摄入量的糖尿全身麻醉就相当于身体死过一次?麻醉后,身体会有什么副作用人生在世,肯定不能事事如意,就比如在饮食方面,食用五谷杂粮难免会出现身体不适。再加上现在人们对养生的重视,当身体出现任何不适,便会及时就医寻求医生的帮助,如果是小病,适当服用药物便那些神仙句子,建议收藏(花店不开了,花继续开)1。我们的认知边界,就是我们世界的边界。2。我沉沦于野火,潮起潮涌,鲸鱼陷落,月亮困束于灯色,江风渔火吐出一万次叹息。3。我花了那么多时间冲淡你,可月亮最后一次引力,就溃不成军。4医生家有小学生4类食物不能少,孩子早餐要吃够营养长个更聪明大家好!我是浩源妈妈养娃过程中,不知道最让您头疼的事情是什么呢?或许您会说学习。可我觉得比起学习,更让我头疼的是孩子的吃饭问题,尤其是早餐。尤其是这大热天儿的,一大早钻进厨房忙活,寿命短的女性,大多早起会有4个习惯,若你一个不占,身体较健康女性寿命相对于男性,的确是稍高一些,却不是说女性都会很长寿,有一些女性不良习惯较多,对健康的影响也就会比较大,寿命也会因为某些疾病大大的缩短。而容易缩短寿命的习惯,可能就是早起后的健康生活早餐喝牛奶就是对身体好?错!4种不恰当的早餐,越吃越不健康早餐提供的营养和能量对人体十分重要。经常不吃早餐,或者早餐吃不好的人,难免会遇到以下3个问题能量和其他营养供应不足增加肥胖糖尿病心脑血管疾病的发生风险影响认知能力,降低大脑功能,使烈日炎炎,这些防晒建议请收下高温天气长时间暴露于日光下会加速人的皮肤老化严重的会引起很多皮肤疾病所以防晒必不可少市面上的防晒产品五花八门有的还宣称加入玻尿酸木糖醇靠谱吗?防晒产品应该如何挑选?购买防晒类产品注芒果台又杀疯了!何炅集齐3大收视保障,那些唱衰的人就要失望了去年,芒果台的王牌节目快乐大本营停播了,有人欢喜有人忧。这些年,芒果台在做综艺方面是当之无愧的老大哥,总能走在最前面,抓住观众的眼球,令竞争对手眼红不已。其实,就算没有新节目,芒果有甲状腺结节不能吃苦瓜吗?少接触5种食物,或有助结节消失患有甲状腺结节的人在日常生活中可适当食用一些苦瓜。苦瓜中含有一定量的微量元素以及营养成分,对患者补充微量元素有积极的意义,而且从中医保健的角度来看,它具有清热解毒的功效。甲状腺结节不停放屁,有可能是身体碰上了这4个麻烦放屁是一种非常正常的人体生理现象,是自然而然就会发生的。而每次的噗噗噗的感受也都不尽相同,有时很痛快,有时声音很大,有时味道很重,那么屁到底是怎么形成的呢?我们身体可以产生气体的地