之前我讲过如何用js绘制矩形框,下面链接快速通道~
那么如何判断多个矩形框是否相交?嵌套还是其他的呢?
那下面我来分别写写关于矩形框常用的几个算法吧
- 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轴
- /**
- * 输出两个矩形交互后的交互矩形坐标,若无则不输出
- * @param rectA 矩形A的详情数据
- * @param rectB 矩形B的详情数据
- */
- intersectRectangle(rectA, rectB) {
- const { startX: xa, startY: ya, width: wa, height: ha } = rectA
- const { startX: xb, startY: yb, width: wb, height: hb } = rectB
- // 以下为矩形A,B的左上和右下两个坐标数据
- const ax1 = xa
- const ay1 = ya
- const ax2 = xa + wa
- const ay2 = ya + ha
- const bx1 = xb
- const by1 = yb
- const bx2 = xb + wb
- const by2 = yb + hb
- const 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]]
- }
- }
- /**
- * 判断两矩形交互的面积占比
- * @param rectA 矩形A的详情数据
- * @param rectB 矩形B的详情数据
- */
- rectangleArea(rectA, rectB) {
- const { width: wa, height: ha } = rectA
- const { width: wb, height: hb } = rectB
- const pointMap = this.intersectRectangle(rectA, rectB) // 交互矩形的坐标集合,如无输出则表示无交互矩形
- let s = 0
- if (!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)) // 重叠面积占比计算,保留三位小数: 重叠面积 / 最小的矩形面积
- }
示例图:

算法源码:
- /**
- * @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
- }
示例图:

算法源码:
- /**
- * @description 判断重叠面积是否小于80%
- * @return boolean true(重叠面积大于80%) false(重叠面积小于80%)
- */
- isOverlapRect() {
- const copyFrame = this.frameList
- let 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%则返回true
- if (flag) break
- }
- if (flag) break
- }
- return flag
- }
示例图:

算法源码:
- /**
- * @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 = false
- for (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
- }
示例图:

算法源码:
- /**
- * @description 分栏框相交部分是否存在嵌套的大题干框
- * @param object 当前框的数据
- * @return boolean true(存在嵌套的大题干框) false(不存在嵌套的大题干框)
- */
- isBorderlineRect(detail) {
- if (detail.type === 0) return false
- const splitFrames = this.frameList.filter(item => (this.answerPages.current === item.pageNo) && (item.type === 0))
- let flag = false
- for (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 = true
- break
- }
- }
- }
- if (flag) break
- }
- return flag
- }
---有不懂的可以随时评论提问噢,我有空会看的噢~---