软件项目技术点(25)——提升性能之检测绘制范围

软件里的一个画面包含很多个元素,但是当缩放到某个局部位置时,需要绘制的元素个数就很少。那么怎么判断某个元素是否需要进行绘制呢?

我们在绘制整个画面时,是进行循环遍历每个元素的,如下判断是否进行绘制的代码:

 1 var elements = this.commonElements.all();//获取所有元素列表
 2 var winInfo = getWindow();//获取画布窗口的宽高值
 3 var viewMinx = 0;
 4 var viewMiny = 0;
 5 var viewMaxx = winInfo.width;
 6 var viewMaxy = winInfo.height;
 7
 8 var windowViewPoints = new Common.List<Core.Point>();//存储窗口矩形四个顶点的坐标值
 9 windowViewPoints.add(new Core.Point(viewMinx, viewMiny));
10 windowViewPoints.add(new Core.Point(viewMaxx, viewMaxy));
11 windowViewPoints.add(new Core.Point(viewMinx, viewMaxy));
12 windowViewPoints.add(new Core.Point(viewMaxx, viewMiny));
13 //循环绘制每个元素
14 for (var key in elements) {
15     var isDraw = false;
16     var config = elements[key].config;
17     if (config.width * that.scale > 20 || config.height * that.scale > 20) {//首先判断该元素宽高不能都低于20像素,控制元素太小时不绘制
18         var points = elements[key].getAllPoints().viewTruePoints;//获取该元素矩形四个点相对于画布窗口的坐标值
19         isDraw = Common.CollisiionDetector._instance.RectToRectCollisionDec(windowViewPoints, points);//判断窗口矩形和元素矩形是否有交叉重叠,决定是否进行绘制
20         if (isDraw) {
21             elements[key].draw(gotoComplete);
22         }
23     }
24 }

矩形间交叉重叠的检测

下面主要介绍判断窗口矩形和元素矩形是否有交叉重叠RectToRectCollisionDec方法是如何实现的?

下面让大家看一个demo,主要展示如果两个矩形同时在旋转,没有重叠时绘制的颜色是蓝色,如果有重叠绘制成红色

实现原理:

  对于两个多边形,如果存在一个轴,使得两个多边形的在该轴上的投影不重叠,则多边形之间没有碰撞发生。

  在这里所有可能的轴是指垂直于多边形每个边的轴

 第一步:我们需要制定哪个轴作为参考轴

 由于矩形对边相互平行,因此平行的两个边共同拥有一条垂直于它们的轴。因此,对于每个矩形,需要用于检测的轴只有两条。我们只需要检测在另一个矩形在该轴上的投影是否和该轴重叠。为了方便,我们可以直接拿矩形相邻的两个边作为两个轴,然后把这两个轴和另一个矩形的四个边作是否有重叠的比较。

RectToRectCollisionDec检测两个矩形是否有重叠交叉:

 1 //获取该矩形上的四条边
 2 private getFourLines(rectPointsArr: List<Core.Point>) {
 3     var p0 = rectPointsArr.get(0);
 4     var p1 = rectPointsArr.get(1);
 5     var p2 = rectPointsArr.get(2);
 6     var p3 = rectPointsArr.get(3);
 7     var l1 = [[p0.x, p0.y], [p1.x, p1.y]];
 8     var l2 = [[p1.x, p1.y], [p2.x, p2.y]];
 9     var l3 = [[p2.x, p2.y], [p3.x, p3.y]];
10     var l4 = [[p3.x, p3.y], [p0.x, p0.y]];
11     return [l1, l2, l3, l4];
12 }
13  //传入两个矩形的四个点,检测两个矩形是否有重叠交叉
14 RectToRectCollisionDec(r1PointArray: List<Core.Point>, r2PointArray: List<Core.Point>) {
15
16     var linesArr1 = this.getFourLines(r1PointArray);//矩形1的四条边
17     var linesArr2 = this.getFourLines(r2PointArray);//矩形2的四条边
18
19     //每个矩形相邻的两个边作为两个轴,分别和另一个矩形的四个边进行投影重叠的比较,如果有一个返回false代表存在一个轴上的投影不重叠,detectAxisCollision函数来检查一个矩形的四边在指定轴上的投影是否和轴线段本身的投影重叠
20     if (this.detectAxisCollision(linesArr2[0], linesArr1) && this.detectAxisCollision(linesArr2[1], linesArr1) && this.detectAxisCollision(linesArr1[0], linesArr2) && this.detectAxisCollision(linesArr1[1], linesArr2)) {
21         return true;
22     }
23     return false;
24
25 }

第二步:检查一个矩形的四条边在指定轴上的投影和轴线段本身在向量上的投影是否有重叠,首先需要获取到一个矩形各个边在该轴上的投影和该轴在该向量上的投影

要获得线段在轴上的投影,我们需要分解为计算线段两个顶点在轴上的投影。如何计算点在轴上的投影?

 1 private getTYPoing(p, axis) {//获取点在轴上的投影点
 2     //顶点在轴上的投影
 3     var x = ((p[0] * axis[0] + p[1] * axis[1]) / (axis[0] * axis[0] + axis[1] * axis[1])) * axis[0];
 4     var y = ((p[0] * axis[0] + p[1] * axis[1]) / (axis[0] * axis[0] + axis[1] * axis[1])) * axis[1];
 5     return [x, y];
 6 }
 7 private getLineTYToAxis(line, axis) {//线到轴的投影
 8
 9     var a = [axis[1][0] - axis[0][0], axis[1][1] - axis[0][1]];//轴向量axis的计算
10     var p0 = line[0];//线的一个顶点0
11     var p1 = line[1];//线的一个顶点1
12     var pt0 = this.getTYPoing(p0, a);
13     var pt1 = this.getTYPoing(p1, a);
14     return [pt0, pt1];
15 }
16   

第三步:计算一条边在指定轴上的投影和轴线段本身在向量上的投影是否有重叠

如何检测线段的重叠?由于这里两个线段是投影在同一个轴向量上,因此他们肯定平行,所以判别方法也比较简单了。方法这里提供一个:线段端点的x轴坐标分别和另一线段的两个端点的x轴坐标相减,得出的两个结果相乘,如果存在结果小于0,则证明线段重叠(当两个线段垂直的时候,使用端点的y轴坐标作判断)

 1 private isLineOverlap(l1, l2) {//判断线段是否重叠
 2
 3     var l1p1 = l1[0], l1p2 = l1[1], l2p1 = l2[0], l2p2 = l2[1];
 4     if (l1p1[0] != l2p1[0]) {//非垂直X轴的两线段
 5         if ((l1p1[0] - l2p1[0]) * (l1p1[0] - l2p2[0]) < 0 || (l1p2[0] - l2p1[0]) * (l1p2[0] - l2p2[0]) < 0 || (l2p1[0] - l1p1[0]) * (l2p1[0] - l1p2[0]) < 0 || (l2p2[0] - l1p1[0]) * (l2p2[0] - l1p2[0]) < 0) {
 6             return true;
 7         }
 8     }
 9     else {//垂直X轴
10         if ((l1p1[1] - l2p1[1]) * (l1p1[1] - l2p2[1]) < 0 || (l1p2[1] - l2p1[1]) * (l1p2[1] - l2p2[1]) < 0 || (l2p1[1] - l1p1[1]) * (l2p1[1] - l1p2[1]) < 0 || (l2p2[1] - l1p1[1]) * (l2p2[1] - l1p2[1]) < 0) {
11             return true;
12         }
13     }
14
15     return false;
16 }

第四步:检查一个矩形的四条边在指定轴上的投影和轴线段本身在向量上的投影是否都不重叠,则没有碰撞,否则产生碰撞。就是第一段代码中函数RectToRectCollisionDec中调用的四次函数detectAxisCollision

线段交叉的检测

软件有也需要判断线段与矩形是否交叉,线段之间是否交叉?

下面先介绍一个函数

CCW(p1, p2, p3): boolean {
     return (p3.y - p1.y) * (p2.x - p1.x) > (p2.y - p1.y) * (p3.x - p1.x);
}

CCW利用叉积的性质,这是图形学的标准算法。 

两个向量的叉积如果是正的,说明是第一个向量转到第二个向量是逆时针方向;反之亦然 
。他的CCW函数就是干这个的。 
用这个可以判断一个点是在线段的左侧还是右侧。 
然后只要判断是否线段A的两个端点在线段B的两侧并且线段B的两个端点也在线段A的两侧就可以了。

线段与线段是否交叉的方法(线段A的两个端点在线段B的两侧并且线段B的两个端点也在线段A的两侧):

LineToLineCollisionDec(line1Start: Core.Point, line1End: Core.Point, line2Start: Core.Point, line2End: Core.Point) {
    return (this.CCW(line1Start, line2Start, line2End) != this.CCW(line1End, line2Start, line2End)) && (this.CCW(line1Start, line1End, line2Start) != this.CCW(line1Start, line1End, line2End));
}

参考资料:碰撞检测作分析:方向包围盒(OBB)碰撞检测  http://www.cnblogs.com/iamzhanglei/archive/2012/06/07/2539751.html

时间: 2024-12-18 06:17:50

软件项目技术点(25)——提升性能之检测绘制范围的相关文章

软件项目技术点(19)——文件的保存和打开(解压缩)

保存文件 保存内容有哪些? 我们需要保存的内容信息 1)context.json 存储画布状态信息和所有元素的配置信息(这个文件在过程中生成) 2)插入的图片.音频.视频等资源 3)所用到的字体文件 4)每一帧的缩略图 将这些文件压缩到一个zip包里,我们的作品保存后的文件是dbk后缀格式的,其实就是一个压缩zip文件. 保存过程步骤解析 1)获取要保存的对象信息dtoCore,后面将其转换成字符串string后存储到文件里. 2)将保存作品用到的资源整理到fileList中,fileList对

提升性能-事件委托技术

--- title: 提升性能——事件委托技术 date: 2016-05-11 22:13:43 tags: [javascript,improving performance, font-end] --- 提升页面性能之事件委托技术 (整理摘选自<Javascript高级程序设计>)概述 利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件. 实际例子 HTML部分 <ul id = "mylinks"> <li id = "g

【.NET Core项目实战-统一认证平台】第十五章 网关篇-使用二级缓存提升性能

原文:[.NET Core项目实战-统一认证平台]第十五章 网关篇-使用二级缓存提升性能 [.NET Core项目实战-统一认证平台]开篇及目录索引 一.背景 首先说声抱歉,可能是因为假期综合症(其实就是因为懒哈)的原因,已经很长时间没更新博客了,现在也调整的差不多了,准备还是以每周1-2篇的进度来更新博客,并完成本项目所有功能. 言归正传,本重构项目是在我根据实际需求重构,由于还未完全写完,所以也没进行压测,在2月份时,张善友老师给我留言说经过压测发现我重构的Ocelot网关功能性能较差,其中

Project Management: 软件项目估算与计划不是一般的难!

摘要:估算.计划.计划跟踪是项目管理的主要工作,难度之高超乎你想象!光靠学习项目管理理论难以管好项目,而往往真能管好项目的都是那些在具体项目中滚打出来的实干人士.本文将会让你全面学习项目估算.计划.计划跟踪的知识,体验实际项目管理的难度,学到提高项目管理水平的一些方法. 大纲:1.从建筑工程说起2.估算要估啥?3.估算如何做出来?4.计划有什么内容?5.计划是如何做出来的?6.如何跟踪计划?7.优秀项目经理是怎样炼成的? 特别声明:如需转载此文,请给出指向本网站的连接,如下:作者:张传波摘自:h

软件项目报价方法

题:软件项目报价方法 广告:========================================================== 欢迎使用[豆瓣读书] 管理你的阅读,查阅书评,编写读书笔记等. ^^ app下载:http://itunes.apple.com/cn/app/id695492935 ================================================================= 软件项目一般包括解决方案.开发.维护.系统集成等.以下

2017.07.07 IT项目管理笔记整理 第八章 软件项目质量管理

软件质量的特性:1.正确性 2.可靠性 3.效率 4.完整性 5.使用性 6.维护性2. 测试性 8.灵活性 9.移植性 10复用性 11.共运行性 软件质量的6个特性用于评价: 1功能性 2.可靠性 3.易用性 4.效率 5.可维护性 6.可移植性 软件质量保证的目标:1通过适当的监控系统及其开发过程来保证软件质量.2确保软件及其开发过程与已定的标准和规程要求完全一致3保证软件及时发现产品.过程和标准的任何不足并提醒管理者注意,以便及时弥补 软件质量保证组织的职责: a对所有开发计划和质量计划

软件项目需求开发过程实践之业务建模用例图

本次软件工程项目是重建办公业务流程管理平台,需要在继承原370个流程基础上,还需要提供快速流程开发能力,并要求体现出流程管理的规范性,以及流程的执行力.效率.效益,最终为企业管理创新提供流程再造的能力. 在项目前期及需求分析阶段,开发人员致力于"降低成本",以最小的代价完成项目,其可预见性的软件产品是经过系统平台升级的,并经过改良的第二个办公业务流程管理平台.按客户验收要求,"只能打60分,是不能给予验收". 在软件开发中,需求工作致力于解决"产品好卖&q

软件项目开发环境构建之一:整体流程

通常情况下,一个大的项目,很难一个人完成,需要一个团队共同协作,大家彼此分工,共同完成不同或相同的模块,这时要求所使用的工具软件要具有分布式协同功能.处理冲突及持续交付功能,一般软件项目的整体流程如下: 一个软件项目的实施,要经过概念阶段.计划阶段.创建阶段.发布阶段及追踪阶段,Atlassion的软件族都有各阶段的对应软件. 一般,概念阶段,可以使用Confluence 进行需求管理,从最初的想法到最终的需求,能够通过Confluence强大的协同功能,高效的完成需求收集.整理.分类等工作(M

软件项目与过程管理第八周作业

内容:软件项目与过程管理课程内容总结 经过八周时间的学习,软件项目与过程管理课程已经逐渐接近了尾声.通过这八周的学习,我对软件项目与过程管理课程有了更深的理解. 一.关于团队项目. 团队项目是本次软件项目与过程管理课程中最重要的一部分.我们团队项目是作业管理系统.在项目开发的整个过程中,我们在项目经理的带领下,项目团队的每一个成员团结合作.相互沟通,团队成员之间相互学习彼此的优点和技术,在每个成员的共同努力下,基本完成了此次软件开发项目. 通过这次团队项目, 我的总结如下: 1.在项目的开发过程