【问题标题】:total area of intersecting rectangles相交矩形的总面积
【发布时间】:2010-12-28 21:09:01
【问题描述】:

我需要一个算法来解决这个问题: 给定 2 个矩形在任何角落相交或重叠在一起,我如何确定没有重叠(相交)区域的两个矩形的总面积?这意味着交叉区域必须计算一次,可以使用第一个矩形,也可以使用第二个矩形。

【问题讨论】:

  • 你有交点的位置吗?

标签: algorithm


【解决方案1】:

这很容易。首先计算交点坐标,也是一个矩形。

left = max(r1.left, r2.left)
right = min(r1.right, r2.right)
bottom = max(r1.bottom, r2.bottom)
top = min(r1.top, r2.top)

然后,如果交集不为空(left < right && bottom < top),则从两个矩形的公共区域中减去它:r1.area + r2.area - intersection.area

PS:

  1. 假设 1: 矩形按坐标轴对齐,通常是这样。
  2. 假设2:这里的y轴是向上增加的,例如在一个图形应用中,y轴是向下增加的,你可能需要使用:

bottom = min(r1.bottom, r2.bottom) top = max(r1.top, r2.top)

【讨论】:

  • 谢谢,但如果您不介意,您能否给出如何在代码中表示矩形,因为用户可以输入矩形的左下边缘和右上边缘,那么如何表示它?
  • 复杂度必须小于O(n^2)
  • @al_khater 当你说 O(n^2) 这里的“n”是什么?您的原始问题中只有两个矩形,这意味着总共只有 8 个点。
  • @al_khater 作为您使用的任何语言的对象。在 javascript 中,它可能看起来像 {left: 100, bottom: 200, right: 300, top: 400}。但是这里没有人会为你写一个完整的应用程序,人们有自己的工作。
  • 您还假设所有矩形的顶部 > 底部,这在图形中通常不是这种情况。否则做得很好!
【解决方案2】:

这里是使用 Java 的该算法的完整解决方案:

public static int solution(int K, int L, int M, int N, int P, int Q, int R,
        int S) {
    int left = Math.max(K, P);
    int right = Math.min(M, R);
    int bottom = Math.max(L, Q);
    int top = Math.min(N, S);

    if (left < right && bottom < top) {
        int interSection = (right - left) * (top - bottom);
        int unionArea = ((M - K) * (N - L)) + ((R - P) * (S - Q))
                - interSection;
        return unionArea;
    }
    return 0;
} 

【讨论】:

    【解决方案3】:

    我看到这个问题没有得到回答,所以我编写了一个小型 Java 程序来尝试 @VicJordan 和 @NikitaRybak 在之前的答案中讨论过的等式。希望这会有所帮助。

    /**
     * This function tries to see how much of the smallest rectangle intersects 
     * the with the larger one. In this case we call the rectangles a and b and we 
     * give them both two points x1,y1 and x2, y2.
     * 
     * First we check for the rightmost left coordinate. Then the leftmost right 
     * coordinate and so on. When we have iLeft,iRight,iTop,iBottom we try to get the 
     * intersection points lenght's right - left and bottom - top.
     * These lenght's we multiply to get the intersection area.
     *
     * Lastly we return the result of what we get when we add the two areas 
     * and remove the intersection area.
     * 
     * @param xa1       left x coordinate   A
     * @param ya1       top y coordinate    A
     * @param xa2       right x coordinate  A
     * @param ya2       bottom y coordinate A
     * @param xb1       left x coordinate   B
     * @param yb1       top y coordinate    B
     * @param xb2       right x coordinate  B
     * @param yb2       bottom y coordinate B
     * @return          Total area without the extra intersection area.
     */
    
    public static float mostlyIntersects(float xa1, float ya1, float xa2, float ya2, float xb1, float yb1, float xb2, float yb2) {
        float iLeft = Math.max(xa1, xb1);
        float iRight = Math.min(xa2, xb2);
        float iTop = Math.max(ya1, yb1);
        float iBottom = Math.min(ya2, yb2);
    
        float si = Math.max(0, iRight - iLeft) * Math.max(0, iBottom - iTop);
        float sa = (xa2 - xa1) * (ya2 - ya1);
        float sb = (xb2 - xb1) * (yb2 - yb1);
    
        return sa + sb - si;
    }
    

    【讨论】:

    • 它应该是 float iTop = Math.min(ya1, yb1); float iBottom = Math.max(ya2, yb2);
    • 嗨@manshu 好吧,我猜它可以转过来。您可能还需要将减法更改为 iTop - iButtom。我正在使用底部为 0 的坐标系编写应用程序,这可能会使算法颠倒过来。
    【解决方案4】:

    如果原点 (0,0) 位于参考系的左下角,则交点坐标正确。

    在图像处理中,原点 (0,0) 通常位于参考系的左上角,交点的坐标底部和顶部将是:

    bottom = min(r1.bottom, r2.bottom)
    top = max(r1.top, r2.top)
    

    【讨论】:

      【解决方案5】:

      具有分析和 LeetCode 测试结果的 Swift 版本解决方案。

      /**
       Calculate the area of intersection of two given rectilinear rectangles.
      
       - Author:
       Cong Liu <congliu0704 at gmail dot com>
      
       - Returns:
       The area of intersection of two given rectilinear rectangles.
      
       - Parameters:
       - K: The x coordinate of the lower left point of rectangle A
       - L: The y coordinate of the lower left point of rectangle A
       - M: The x coordinate of the upper right point of rectangle A
       - N: The y coordinate of the upper right point of rectangle A
       - P: The x coordinate of the lower left point of rectangle B
       - Q: The y coordinate of the lower left point of rectangle B
       - R: The x coordinate of the upper right point of rectangle B
       - S: The y coordinate of the upper right point of rectangle B
      
       - Assumptions:
       All the eight given coordinates (K, L, M, N, P, Q, R and S) are integers
       within the range [-2147483648...2147483647], that is, Int32-compatible.
       K < M, L < N, P < R, Q < S
      
       - Analysis:
       The area of intersected is dyIntersected * dxIntersected.
      
       To find out dyIntersected, consider how y coordinates of two rectangles relate
       to each other, by moving rectangle A from above rectangle B down.
      
       Case 1: when N >  L >= S >  Q, dyIntersected = 0
       Case 2: when N >= S >  L >= Q, dyIntersected = S - L
       Case 3: when S >  N >  L >= Q, dyIntersected = N - L
       Case 4: when S >= N >= Q >  L, dyIntersected = N - Q
       Case 5: when N >  S >  Q >  L, dyIntersected = S - Q
       Cases 2 and 3 can be merged as Case B:
               when           L >= Q, dyIntersected = min(N, S) - L
       Cases 4 and 5 can be merged as Case C:
               when           Q >  L, dyIntersected = min(N, S) - Q
       Cases B and C can be merged as Case D:
               when      S >  L     , dyIntersected = min(N, S) - max(L, Q)
      
       Likewise, x coordinates of two rectangles relate similarly to each other:
       Case 1: when R >  P >= M >  K, dxIntersected = 0
       Case 2: when      M >  P     , dxIntersected = min(R, M) - max(P, K)
      
       - Submission Date:
       Sat 20 Jan 2018 CST at 23:28 pm
      
       - Performance:
       https://leetcode.com/problems/rectangle-area/description/
       Status: Accepted
       3081 / 3081 test cases passed.
       Runtime: 78 ms
       */
      class Solution {
        public static func computeArea(_ K: Int, _ L: Int, _ M: Int, _ N: Int, _ P: Int, _ Q: Int, _ R: Int, _ S: Int) -> Int {
          let areaA : Int = Int((M - K) * (N - L))
          let areaB : Int = Int((R - P) * (S - Q))
          var xIntersection : Int = 0
          var yIntersection : Int = 0
          var areaIntersection : Int = 0
      
          if ((min(M, R) - max(K, P)) > 0) {
            xIntersection = Int(min(M, R) - max(K, P))
          }
      
          if ((min(N, S) - max(L, Q)) > 0) {
            yIntersection = Int(min(N, S) - max(L, Q))
          }
      
          if ((xIntersection == 0) || (yIntersection == 0)) {
            areaIntersection = 0
          } else {
            areaIntersection = Int(xIntersection * yIntersection)
          }
      
          return (areaA + areaB - areaIntersection)
        }
      }
      
      // A simple test
      Solution.computeArea(-4, 1, 2, 6, 0, -1, 4, 3) // returns 42
      

      【讨论】:

        【解决方案6】:

        很抱歉来晚了。 我不知道您是否正在寻找特定语言: 但在 iOS 上它非常简单:

        CGRectIntersection

        https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGGeometry/#//apple_ref/c/func/CGRectIntersection

        它会给你与给定两个矩形重叠的 CGrect。 如果它们不相交,则返回 CGRectIsNull

        希望这至少对某人有所帮助。快乐编码

        【讨论】:

          猜你喜欢
          • 2018-07-17
          • 1970-01-01
          • 1970-01-01
          • 2021-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多