前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于判断两个矩形是否相交

关于判断两个矩形是否相交

作者头像
Yiiven
发布2022-12-15 15:09:56
2K0
发布2022-12-15 15:09:56
举报
文章被收录于专栏:怡文菌怡文菌

探究

最近在做WEB前端项目时,需要识别一个元素是否有某些部位出现在可视区域内,当有某个部位出现在可视区域时,就执行该元素绑定的动画,如果完全不在可视区域内则移除其动画,当再次出现时重复执行动画。

众所周知,元素是以一个矩形的盒模型的形式呈现在网页中,而且浏览器的可视区域也是一个矩形,那么这个需求就变成了某个元素的盒模型(矩形B)是否有某个部分出现在浏览器可视区域(矩形A)中,如果有则执行动画。

将需求提炼一下,问题为:判断矩形APa1(Xa1,Ya1), Pa2(Xa2,Ya2)与矩形BPb1(Xb1,Yb1), Pb2(Xb2,Yb2)是否相交。

图1

最初的思路如下:

  1. 首先求出点Pa1Pb1距离原点(0,0)更远的点(即x轴方向与y轴方向坐标值较大的点),将其标记为M(图1的中粉色点);
  2. 然后求出Pa2Pb2距离原点更近的点(即x轴方向与y轴方向坐标值较小的点),将其标记为N(图1中的橙色点);
  3. 判断:如果点M的x轴坐标值和y轴坐标值均比点N的x轴坐标和y轴坐标小(即,M点和N点可以构成一个新的矩形),则两个矩形相交,否则不相交。

方法出来了,总要经过验证才知道是否正确,那么接下来就对以下几种情况进行验证:

几种相交的情况:

图2

图3

图4

图5

再举两个不相交的情况:

图6

图7

如上所示,除了图1、图2通过上述方法得出正确答案外,其他情况均无法得出正确答案,由此可见上述方法是错误的。

那么如何才能得到正确的方法呢?仔细观察上面列出的几种情况后,想到了一个新的思路:如果两个矩形相交,那么矩形A的中心点Pa3(Xa3,Ya3)与矩形B的中心点Pb3(Xb3,Yb3)在x轴方向上的距离和y轴方向的距离一定满足以下条件:

  • 在x轴方向:Pa3Pb3的距离一定小于或等于矩形A的宽度+矩形B的宽度的一半;
  • 在y轴方向:Pa3Pb3的距离一定小于或等于矩形A的高度+矩形B的高度的一半;

只要满足以上两个条件,那么就可以判定为两个矩形相交。

代码语言:javascript
复制
矩形A
宽:Wa = Xa2 - Xa1
高:Ha = Ya2 - Ya1
中心坐标:[Xa3, Ya3] = [(Xa2 + Xa1) / 2, (Ya2 + Ya1) / 2]


矩形B
宽:Wb = Xb2 - Xb1
高:Hb = Yb2 - Yb1
中心坐标:[Xb3, Yb3] = [(Xb2 + Xb1) / 2, (Yb2 + Yb1) / 2]

上述两个条件即可表示为
1) |Xb3 - Xa3| <=  Wa/2 + Wb/2
2) |Yb3 - Ya3| <=  Ha/2 + Hb/2

再代入宽、高、中心点坐标计算公式并简化,即为:
1) |Xb2 + Xb1 - Xa2 - Xa1| <=  Xa2 - Xa1 + Xb2 - Xb1
2) |Yb2 + Yb1 - Ya2 - Ya1| <=  Ya2 - Ya1 + Yb2 - Yb1

扩展

如果想要得到相交区域的新矩形,那么需要取得相交区域的左上角顶点与右下角坐标,有方法如下:

代码语言:javascript
复制
设相交区域的新矩形为c[(Xc1,Yc1), (Xc2,Yc2)]

Xc1 = max(Xa1,Xb1)
Yc1 = max(Ya1,Yb1)

Xc2 = min(Xa2,Xb2)
Yc2 = min(Xa2,Xb2)

也可以通过判断上述获取新矩形的方法来判定两个矩形是否相交,方法如下: 若同时满足以下两个条件,则可以判定两个矩形相交。 1) Xc1 <= Xc2 2) Yc1 <= Yc2 即: max(Xa1,Xb1) <= min(Xa2,Xb2) max(Ya1,Yb1) <= min(Ya2,Yb2)

编码

根据以上结论,有如下javascript代码提供参考:

代码语言:javascript
复制
/*
 * rect obj {x1:num, y1:num, x2:num, y2:num} 定义矩形的两个顶点的坐标集合
 */
var isIntersection = function(rectA, rectB){
    let lftp = [Math.max(rectA.x1, rectB.x1), Math.max(rectA.y1, rectB.y1)],
        rgbt = [Math.min(rectA.x2, rectB.x2), Math.min(rectA.y2, rectB.y2)];
    if(lftp[0] <= rgbt[0] && lftp[1] <= rgbt[1]){
        return true;
    }
    return false;
}

var rectA = {x1: 6, y1: 6, x2: 14, y2: 12},
    rectB = {x1: 10, y1: 10, x2: 20, y2: 16},
    rectC = {x1: 8, y1: 8, x2: 12, y2: 10},
    rectD = {x1: 4, y1: 8, x2: 16, y2: 10},
    rectE = {x1: 8, y1: 8, x2: 12, y2: 16},
    rectF = {x1: 10, y1: 14, x2: 16, y2: 18},
    rectG = {x1: 16, y1: 10, x2: 20, y2: 18};

console.log(isIntersection(rectA, rectB));  // true
console.log(isIntersection(rectA, rectC));  // true
console.log(isIntersection(rectA, rectD));  // true
console.log(isIntersection(rectA, rectE));  // true
console.log(isIntersection(rectA, rectF));  // false
console.log(isIntersection(rectA, rectG));  // false

特别注意:以上结论若要成立,还有一个**先决条件**,即:两个矩形均为与轴对齐的矩形,否则将不适用,例如矩形B被旋转后,如图8、图9:

图8

图9

本文采用 「CC BY-NC-SA 4.0」创作共享协议,转载请标注以下信息:

原文出处:Yiiven https://cloud.tencent.com/developer/article/2193257

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 探究
  • 扩展
  • 编码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档