有趣且重要的JS知识合集(17)矩形框交互算法
创始人
2024-03-12 10:54:24
0

之前我讲过如何用js绘制矩形框,下面链接快速通道~

【JS】原生js实现矩形框的绘制/拖动/缩放

那么如何判断多个矩形框是否相交?嵌套还是其他的呢?

那下面我来分别写写关于矩形框常用的几个算法吧

1、数据格式知悉

const { startX, startY, width, height, type } = rectangle// startX 矩形框左上角X轴
// startY 矩形框左上角Y轴
// width 矩形框宽
// height 矩形框高
// type 矩形框类型frameList: 矩形框列表,里面有多个rectangle对象
detail:下面算法中实参中有detail代表他是在拿detail和其他矩形框进行对比,detail也是一个rectangle对象哦

其实根据上述数据,我们能得到矩形框的左上角和右下角坐标是

x1 = startX // 矩形框左上角X轴
y1 = startY // 矩形框左上角Y轴
x2 = startX + width // 矩形框右下角X轴
y2 = startY + height // 矩形框右下角Y轴

2、算法源码及解析

2.1、输出两个矩形交互后的交互矩形坐标,若无则不输出(核心算法)

    /*** 输出两个矩形交互后的交互矩形坐标,若无则不输出* @param rectA 矩形A的详情数据* @param rectB 矩形B的详情数据*/intersectRectangle(rectA, rectB) {const { startX: xa, startY: ya, width: wa, height: ha } = rectAconst { startX: xb, startY: yb, width: wb, height: hb } = rectB// 以下为矩形A,B的左上和右下两个坐标数据const ax1 = xaconst ay1 = yaconst ax2 = xa + waconst ay2 = ya + haconst bx1 = xbconst by1 = ybconst bx2 = xb + wbconst by2 = yb + hbconst a = Math.max(ax1, bx1)const b = Math.min(ay2, by2)const c = Math.min(ax2, bx2)const d = Math.max(ay1, by1)if (a > c || b < d) { // 符合此条件证明无交互矩形return} else { // 输出交互矩形的左上和右下角坐标return [[a, d], [c, b]]}}

2.2、输出两矩形交互的面积占最小矩形比例(核心算法)

    /*** 判断两矩形交互的面积占比* @param rectA 矩形A的详情数据* @param rectB 矩形B的详情数据*/rectangleArea(rectA, rectB) {const { width: wa, height: ha } = rectAconst { width: wb, height: hb } = rectBconst pointMap = this.intersectRectangle(rectA, rectB) // 交互矩形的坐标集合,如无输出则表示无交互矩形let s = 0if (!pointMap) { // 符合此条件证明无交互面积s = 0;} else { // 计算交互矩形面积s = (pointMap[1][0] - pointMap[0][0]) * (pointMap[1][1] - pointMap[0][1]);}return Number((s / Math.min(wa * ha, wb * hb)).toFixed(3)) // 重叠面积占比计算,保留三位小数: 重叠面积 / 最小的矩形面积}

2.3、判断当前点击的矩形框是否和其他矩形框嵌套

示例图:

算法源码:

    /*** @description 判断是否嵌套* @param object 当前矩形框全部数据* @return boolean true(存在嵌套) false(不存在嵌套)*/isContainRect(detail) {const { startX, startY, width, height } = detail;const copyFrame = this.frameList.filter(item => (item.id !== detail.id))let _status = false;for (let m = 0; m < copyFrame.length; m++) {const { startX: originStartX, startY: originStartY, width: originWidth, height: originHeight } = copyFrame[m];// 大框往小框外嵌套const scene1 = (originStartX - 1 <= startX + width && startX + width <= originStartX + originWidth + 1) && (originStartY - 1 <= startY + height && startY + height <= originStartY + originHeight + 1) && (originStartX < startX && originStartY < startY)// 小框往大框内嵌套const scene2 = (startX - 1 <= originStartX + originWidth && originStartX + originWidth <= startX + width + 1) && (startY - 1 <= originStartY + originHeight && originStartY + originHeight <= startY + height + 1) && (startX < originStartX && startY < originStartY)if (scene1 || scene2) {_status = true;break}}return _status}

2.4、多个矩形框判断是否有重叠,并且重叠面积是否大于80%

示例图:

 

算法源码:

    /*** @description 判断重叠面积是否小于80%* @return boolean true(重叠面积大于80%) false(重叠面积小于80%)*/isOverlapRect() {const copyFrame = this.frameListlet flag = false;for (let i = 0; i < copyFrame.length; i++) { // 矩形框框两两对比,判断是否有交互的地方,有则将交互矩形输出出来for (let j = 0; j < copyFrame.length - 1 - i; j++) {const before = copyFrame[i]const after = copyFrame[i + 1 + j]flag = this.rectangleArea(before, after) > 0.8 // 最小面积占比超过80%则返回trueif (flag) break}if (flag) break}return flag}

2.5、 多种类型的矩形框是否有相交的部分(此处举例两种类型)

示例图:

 

算法源码:

    /*** @description 大题干框 type 为1 和分栏框 type 为0 是否有相交的部分* @return boolean true(有相交部分) false(无相交部分,占比0%或者100%)*/isIntersectRect(detail) {const bigFrames = this.frameList.filter(item => (detail.id !== item.id) &&(item.type === 1))const splitFrames = this.frameList.filter(item => (this.answerPages.current === item.pageNo) && (item.type === 0))let flag = falsefor (let i = 0; i < bigFrames.length; i++) {for (let j = 0; j < splitFrames.length; j++) {const area = this.rectangleArea(bigFrames[i], splitFrames[j])flag = !(area === 0 || area === 1)if (flag) break}if (flag) break}return flag}

2.6、两个同类型矩形框相交部分是否存在嵌套的另种类型框

示例图:

算法源码: 

    /*** @description 分栏框相交部分是否存在嵌套的大题干框* @param object 当前框的数据* @return boolean true(存在嵌套的大题干框) false(不存在嵌套的大题干框)*/isBorderlineRect(detail) {if (detail.type === 0) return falseconst splitFrames = this.frameList.filter(item => (this.answerPages.current === item.pageNo) && (item.type === 0))let flag = falsefor (let i = 0; i < splitFrames.length; i++) { // 分栏框两两对比,判断是否有交互的地方,有则将交互矩形输出出来for (let j = 0; j < splitFrames.length - 1 - i; j++) {const before = splitFrames[i]const after = splitFrames[i + 1 + j]const newRect = this.intersectRectangle(before, after) // 返回的数据为二维坐标数组,需要转换组装新的类坐标格式if (newRect) {const newDecorateRect = { // 类坐标格式startX: newRect[0][0],startY: newRect[0][1],width: newRect[1][0] - newRect[0][0],height: newRect[1][1] - newRect[0][1]}const area = this.rectangleArea(newDecorateRect, detail)if (area === 1) { // 如果有嵌套,则退出循环flag = truebreak}}}if (flag) break}return flag}

---有不懂的可以随时评论提问噢,我有空会看的噢~---

相关内容

热门资讯

美国2年期国债收益率上涨15个... 原标题:美国2年期国债收益率上涨15个基点 美国2年期国债收益率上涨15个基...
汽车油箱结构是什么(汽车油箱结... 本篇文章极速百科给大家谈谈汽车油箱结构是什么,以及汽车油箱结构原理图解对应的知识点,希望对各位有所帮...
嵌入式 ADC使用手册完整版 ... 嵌入式 ADC使用手册完整版 (188977万字)💜&#...
重大消息战皇大厅开挂是真的吗... 您好:战皇大厅这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...
盘点十款牵手跑胡子为什么一直... 您好:牵手跑胡子这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游...
senator香烟多少一盒(s... 今天给各位分享senator香烟多少一盒的知识,其中也会对sevebstars香烟进行解释,如果能碰...
终于懂了新荣耀斗牛真的有挂吗... 您好:新荣耀斗牛这款游戏可以开挂,确实是有挂的,需要了解加客服微信8435338】很多玩家在这款游戏...
盘点十款明星麻将到底有没有挂... 您好:明星麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【5848499】很多玩家在这款游戏...
总结文章“新道游棋牌有透视挂吗... 您好:新道游棋牌这款游戏可以开挂,确实是有挂的,需要了解加客服微信【7682267】很多玩家在这款游...
终于懂了手机麻将到底有没有挂... 您好:手机麻将这款游戏可以开挂,确实是有挂的,需要了解加客服微信【8435338】很多玩家在这款游戏...