专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

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

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

临沂大学的泰山学院济宁学院枣庄学院滨州学院菏泽学院的专科中,哪个更好?感谢邀请!楼主这个问题问的比较含糊,没说多少分,也没说什么专业,所以没法很确切地给你定位。首先这几个院校都是山东省的二本院校,这几年临沂大学的层次略高一点,其余的都是学院级别的,都社保缴费从2013年一次性缴足15年年限,今年办退休,养老金是多少?2013年62000元买15年,今年养老金多少?题主只提供了一个,社保缴费从2013年一次性缴足15年年限,问今年办退休,养老金是多少?如果你能一次性定缴62000元,缴足15年年在殡仪馆上班的女人,胆子能有多大?前女友是殡仪馆的化妆师,她说晚上有好事,喜欢上夜班。有一天晚上我陪她一起值班,半夜3点,我迷迷糊糊睁开眼,转眼瞄了一眼监控,吓得我直打哆嗦。那是2016年的时候,因为一场朋友聚会认大一的绩点排名已经大致确定分水岭了吗?你好,很高兴能够回答你的问题。作为一名大二的学姐,我想和你说的是大一的绩点也不能完全的确定分水岭,即便题主认为可以造成分水岭,也并非是一件坏事,因为分水岭也可以分为成绩和才能的分水国家有没有专门针对老年人的补贴?在农村一辈子从事农业劳动的老农民,特别是405O6O年代的老农民,为国家做出了杰出的农业贡献,他们用无悔的青春为今天的新农民奠是了强大的农业基础,为祖国的建设立下了汗马功劳,在世界报考军校好还是警校好以后就业?作为一名警校毕业生和现役12年的老兵,我不得不纠正一个错误的思想我们不是为了就业而就业,而是为了更美好的生活而就业。这里所谓的美好生活,包含了幸福指数。我是职场取经阁,我警校毕业后西安最著名的十大名校,你都知道几所?你在这些学校上过学吗?我女儿是2019年从陕西师范大学毕业的公费师范生,2019年应聘到成都一所公办初中,离开了我们这个5线城市,到新一线的成都教书,的确有幸运成分,更有她本人的努力成分。西安是全国高校无锡那边的彩礼大概多少钱?办酒席也要男方出钱吗?我是土生土长的无锡人,我以锡山区为例,首先既然你想取无锡本地的女的,我是89年的,而且我家家境一般,我13年结婚的时候彩礼是15。8w,不算金器和婚戒,金器一般就是三件套,具体自己你听过最暖心的话是什么?儿啊,你要是累了,就在饭菜里放些药,妈妈一定吃,躺在这里七年,值了这是一位截瘫的母亲,对不离不弃照顾自己七年多的儿子,说的最暖心也是最绝情的一句话。这位58岁的母亲,瘫痪在床250如果有五百万存在银行,光吃利息能过上什么样的生活?如果现在往银行存500万,然后靠吃银行利息过日子,靠这个利息过生活都挺好的,最起码可以过上小康生活。有500万存银行吃利息,到底能过上什么样的生活,首先要计算出500万一年有多少利如果有人资助你开公司,前提是你每月只能拿一万工资。赚多赚少都是拿这些,你愿意吗?我看到这个问题,我真的是乐开花了,我不是取笑,是真的开心啊。我目前一个人在做淘宝,我的货源是从我朋友那里拿的,做包装袋子的。2014年,我当时在广州一家公司上班,工资有3千多,我朋
庙号之中太祖含金量最高,高祖次之,太宗能排第四,第三是哪个?庙号是中国古代皇帝死后在庙中被供奉时所称呼的名号,起源于商朝。以唐朝为分界线,唐朝之前,除却割据政权不讲规则的滥用,庙号的使用还是很严格的。像西汉12帝,只有4帝有庙号,连汉景帝这美媒预测202223赛季最好的25名得分后卫,按实力排名谁被低估了202122赛季结束后,我们可以看到不少球队针对球队阵容进行了升级补强,特别是得分这一块。2022年休赛季,像老鹰和骑士都对自己得分后卫的球员进行了替补。可见现在得分后卫也依旧是NIFA2022中国头部家电企业展现高超实力2022年9月2日6日,2022年柏林消费电子产品及家用电器展览会(简称IFA2022)在德国柏林举行。一年一度的IFA展是世界上规模最大品类最齐全的电子消费展之一。IFA2022收购德邦后,京东物流实力彻底暴露收购德邦后,京东快运爆发式增长半年前,市场上爆出京东收购德邦的传言,业内普遍认为,此举将补足京东在快运领域的短板。半年后,收购案步入尾声,京东的快运实力,也出现爆发式增长趋势。近日买手机没必要盲目追新,这4款老旗舰凭实力捡漏,流畅再用3年买手机没必要盲目追新,这4款老旗舰凭实力捡漏,流畅再用3年第一款荣耀Magic3Pro内置4600mAh电池,支持66W有线快充以及50W无线快充。后置相机模组,5000万像素主摄油价调整消息今天9月2日,调整后全国92号95号汽油零售价格油价调整计价周期照常运行,马上就要到休息日了,根据数据显示,截至本计价周期的第7个工作日,原油综合变化率4。99,下一轮成品油调价窗口将于9月6日24时开启。现在油价调整幅度达到了男篮欧洲杯第6日戈贝尔两双率法国赢球小萨一扫低迷北京时间9月7日,2022年男篮欧洲杯进入第6个比赛日,在今天,总共进行了12场比赛。以下是详细内容1。立陶宛8764匈牙利在B组的一场对决中,立陶宛8764击败匈牙利。此役,立陶天能股份披露2022年半年报实现营收172。27亿元8月26日,A股上市公司天能股份(代码688819。SH)发布2022年半年度业绩报告。2022年1月1日2022年6月30日,公司实现营业收入172。27亿元,同比增长5。98,上半年网上立案31。38万件河北省法院网上诉讼服务全面加强我省法院网上诉讼服务全面加强今年上半年共网上立案31。38万件,网上开庭10。71万次,在线调解27。53万件从省法院获悉,今年上半年,全省法院加强民生司法保障,服务保障20项民心唐山打人案最新进展,河北省公安厅官员透露主犯陈继志部分信息唐山打人案最新进展,河北省公安厅官员透露主犯陈继志部分信息从唐山打人到现在,已过去65天了,被打女孩一直没有露面,就连被打的两个女孩和四个被打女孩的家庭也没有发出任何声音。就连那个蒋军师长被俘,徐向前答应放人,为何最终仍然枪决?作者东旭子敬,救我!什么条件我都能答应!1931年3月的一天,湖北省广水的双桥镇一家低矮黑暗的农舍,一位灰头土脸的蒋军师长向一位红军将领扑通一声跪下,声音颤抖地说。老军长,快起来,
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网