• 有趣且重要的JS知识合集(17)矩形框交互算法


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

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

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

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

    1、数据格式知悉

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

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

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

    2、算法源码及解析

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

    1. /**
    2. * 输出两个矩形交互后的交互矩形坐标,若无则不输出
    3. * @param rectA 矩形A的详情数据
    4. * @param rectB 矩形B的详情数据
    5. */
    6. intersectRectangle(rectA, rectB) {
    7. const { startX: xa, startY: ya, width: wa, height: ha } = rectA
    8. const { startX: xb, startY: yb, width: wb, height: hb } = rectB
    9. // 以下为矩形A,B的左上和右下两个坐标数据
    10. const ax1 = xa
    11. const ay1 = ya
    12. const ax2 = xa + wa
    13. const ay2 = ya + ha
    14. const bx1 = xb
    15. const by1 = yb
    16. const bx2 = xb + wb
    17. const by2 = yb + hb
    18. const a = Math.max(ax1, bx1)
    19. const b = Math.min(ay2, by2)
    20. const c = Math.min(ax2, bx2)
    21. const d = Math.max(ay1, by1)
    22. if (a > c || b < d) { // 符合此条件证明无交互矩形
    23. return
    24. } else { // 输出交互矩形的左上和右下角坐标
    25. return [[a, d], [c, b]]
    26. }
    27. }

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

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

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

    示例图:

    算法源码:

    1. /**
    2. * @description 判断是否嵌套
    3. * @param object 当前矩形框全部数据
    4. * @return boolean true(存在嵌套) false(不存在嵌套)
    5. */
    6. isContainRect(detail) {
    7. const { startX, startY, width, height } = detail;
    8. const copyFrame = this.frameList.filter(item => (item.id !== detail.id))
    9. let _status = false;
    10. for (let m = 0; m < copyFrame.length; m++) {
    11. const { startX: originStartX, startY: originStartY, width: originWidth, height: originHeight } = copyFrame[m];
    12. // 大框往小框外嵌套
    13. const scene1 = (originStartX - 1 <= startX + width && startX + width <= originStartX + originWidth + 1) && (originStartY - 1 <= startY + height && startY + height <= originStartY + originHeight + 1) && (originStartX < startX && originStartY < startY)
    14. // 小框往大框内嵌套
    15. const scene2 = (startX - 1 <= originStartX + originWidth && originStartX + originWidth <= startX + width + 1) && (startY - 1 <= originStartY + originHeight && originStartY + originHeight <= startY + height + 1) && (startX < originStartX && startY < originStartY)
    16. if (scene1 || scene2) {
    17. _status = true;
    18. break
    19. }
    20. }
    21. return _status
    22. }

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

    示例图:

    算法源码:

    1. /**
    2. * @description 判断重叠面积是否小于80%
    3. * @return boolean true(重叠面积大于80%) false(重叠面积小于80%)
    4. */
    5. isOverlapRect() {
    6. const copyFrame = this.frameList
    7. let flag = false;
    8. for (let i = 0; i < copyFrame.length; i++) { // 矩形框框两两对比,判断是否有交互的地方,有则将交互矩形输出出来
    9. for (let j = 0; j < copyFrame.length - 1 - i; j++) {
    10. const before = copyFrame[i]
    11. const after = copyFrame[i + 1 + j]
    12. flag = this.rectangleArea(before, after) > 0.8 // 最小面积占比超过80%则返回true
    13. if (flag) break
    14. }
    15. if (flag) break
    16. }
    17. return flag
    18. }

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

    示例图:

    算法源码:

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

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

    示例图:

    算法源码: 

    1. /**
    2. * @description 分栏框相交部分是否存在嵌套的大题干框
    3. * @param object 当前框的数据
    4. * @return boolean true(存在嵌套的大题干框) false(不存在嵌套的大题干框)
    5. */
    6. isBorderlineRect(detail) {
    7. if (detail.type === 0) return false
    8. const splitFrames = this.frameList.filter(item => (this.answerPages.current === item.pageNo) && (item.type === 0))
    9. let flag = false
    10. for (let i = 0; i < splitFrames.length; i++) { // 分栏框两两对比,判断是否有交互的地方,有则将交互矩形输出出来
    11. for (let j = 0; j < splitFrames.length - 1 - i; j++) {
    12. const before = splitFrames[i]
    13. const after = splitFrames[i + 1 + j]
    14. const newRect = this.intersectRectangle(before, after) // 返回的数据为二维坐标数组,需要转换组装新的类坐标格式
    15. if (newRect) {
    16. const newDecorateRect = { // 类坐标格式
    17. startX: newRect[0][0],
    18. startY: newRect[0][1],
    19. width: newRect[1][0] - newRect[0][0],
    20. height: newRect[1][1] - newRect[0][1]
    21. }
    22. const area = this.rectangleArea(newDecorateRect, detail)
    23. if (area === 1) { // 如果有嵌套,则退出循环
    24. flag = true
    25. break
    26. }
    27. }
    28. }
    29. if (flag) break
    30. }
    31. return flag
    32. }

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

  • 相关阅读:
    【Stable Diffusion】入门-03:图生图基本步骤+参数解读
    【C语言学习笔记---内存函数】
    【文末附资料链接】2023年第十三届亚太杯数学建模竞赛(APMCM)优秀参考论文思路指导(持续更新中ing)
    Go 学习之 io.Reader 从源码了解如何编写
    SpringBoot集成swagger
    浅浅的 Cmake
    小白备战大厂算法笔试(八)——搜索
    TouchGFX之二进制字体
    【学习笔记】搜索
    Android开发之百度地图定位
  • 原文地址:https://blog.csdn.net/qq_39404437/article/details/128132955