AxeSlide软件项目梳理   canvas绘图系列知识点整理

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

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

 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

转载于:https://www.cnblogs.com/fangsmile/p/6283580.html

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

  1. 软件项目技术点(21)——自动保存和恢复

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 自动保存的基本思路 1)软件每次打开都会创建一个保存画布元素信息的文件,文件名是在打开软件时生成的唯一字符串.可同时打开多个窗口,所以 ...

  2. 软件项目技术路线图_创建基本的项目路线图

    软件项目技术路线图 Continuing from my previous article, at this checkpoint, I have two things with me: 上一篇文章的 ...

  3. 软件项目技术路线图_为您的项目创建路线图

    软件项目技术路线图 Scrum has a tool for roadmap and release planning as well. We use two different mechanisms ...

  4. 做软件项目验收测评,首选专业第三方软件检测机构

    软件项目验收测评,首选专业第三方软件检测机构 卓码软件测评 作者: 卓码软件测评 10-21 13:44 什么是软件项目验收测评?专业第三方软件检测机构怎么收费? 在软件测试行业,最常见的就是验收测试 ...

  5. 软件项目技术点(1)——Tween算法及缓动效果

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 Tween算法及缓动效果 软件里在切换步序时需要有过渡动画效果,从当前位置的画面缓动到目标位置的画面.动画效果可重新查看文章系列第一篇 ...

  6. 软件项目技术点(7)——在canvas上绘制自定义图形

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 图形种类 目前我们软件可以绘制出来的形状有如下这几种,作为开发者我们一直想支持用户可以拖拽的类似word里面图形库,但目前还没有找到比 ...

  7. 软件项目技术点(20)——导出视频

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 导出的视频和播放器自动播放效果时一样的,这样用户就可以传到视频网站分享出去,或者mp4文件发送分享给朋友. 导出视频过程 我们导出视频 ...

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

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 保存文件 保存内容有哪些? 我们需要保存的内容信息 1)context.json 存储画布状态信息和所有元素的配置信息(这个文件在过程 ...

  9. 软件项目技术点(1)——d3.interpolateZoom-在两个点之间平滑地缩放平移

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 软件参考d3的知识点 我们在软件中主要用到d3.js的核心函数d3.interpolateZoom - 在两个点之间平滑地缩放平移.请 ...

最新文章

  1. 零基础Java学习之封装
  2. 转 AIX7.2+11.2.0.4RAC实施
  3. c++ getline 读不到东西_C++ getline()函数问题
  4. 需求用例分析之四:业务规则
  5. 浅析网站SEO与网站建设密不可分的关系
  6. Android知识点剖析系列:深入了解layout_weight属性
  7. 过来人告诉你Python应该这么学
  8. 对promise.all底层的实现的研究
  9. Android 路由实践(二)
  10. python numpy ndarray之basic operations
  11. ##CSP 201512-3 画图(C语言)
  12. caffe数据格式(Google Protocol Buffers)
  13. mongodb sharding maintenance (分片维护1)
  14. 高斯过程回归(Gaussian process regression)原理详解及python代码实战
  15. 计算机 人脑 发热 ppt,人脑即电脑,疯狂的大脑进化史,大脑科学的革命
  16. 获取svg元素的高度和宽度(或其他属性)
  17. happy hacking keybord(hhkb pro)键盘 翻新真假判别(realforce键盘也一样)
  18. 计算复杂性第九章——难解性
  19. 大数据入门之分布式计算框架Spark(2) -- Spark SQL
  20. 流利阅读 2019.1.5 Gatekeeper at Japan’s ‘Suicide Forest’ hopes music can save lives

热门文章

  1. 什么是 Windows Admin Center?
  2. python 切割大文件
  3. cas99970-84-0|2,2‘-联吡啶-4,4’-二甲醛 中间体材料
  4. 【UE4】查找Actor的方法(蓝图)
  5. 一,WIFI基础知识
  6. master slavle mysql_MySQL 不停服务来启用 innodb_file_per_table
  7. linux 查看隐藏文件大小
  8. android蓝牙 相机,android – 如何通过蓝牙访问相机?
  9. 深度整理 | 欧盟《一般数据保护法案》(GDPR)核心要点
  10. 数字IC面经汇总(20篇)