虽然给出的公认答案是正确的,但我认为值得以一种使答案的基本原理完全显而易见的方式探索这个答案。这是一种太常见的算法,无法给出不完整(或更糟糕,有争议)的答案。此外,只看一眼给定的公式,您可能会错过算法的美感和可扩展性,以及正在做出的隐含决策。
首先,考虑一种定义二维盒子的方法:
- (x, y) 表示左上角
- (x, y) 表示右下角
这可能看起来像:
我用三角形表示左上角,用圆圈表示右下角。这是为了避免在本例中出现像 x1, x2 这样的不透明语法。
两个重叠的矩形可能如下所示:
请注意,要找到重叠部分,您正在寻找橙色和蓝色碰撞的地方:
一旦你认识到这一点,很明显重叠是找到并相乘这两条暗线的结果:
每条线的长度是两个圆点的最小值,减去两个三角形点的最大值。
在这里,我使用了两个色调的三角形(和圆形)来显示橙色点和蓝色点是相互比较的。双色三角形后面的小写字母“y”表示沿y轴比较三角形,小“x”表示沿x轴比较。
例如,要查找深蓝色线的长度,您可以查看三角形进行比较以查找两者之间的最大值。比较的属性是 x 属性。三角形之间的最大 x 值为 210。
另一种说法是:
通过从直线最远侧的最近点减去直线最近侧的最远点,得到同时适合橙色线和蓝色线的新线的长度。
找到这些线可以提供有关重叠区域的完整信息。
一旦你有了这个,找出重叠的百分比是微不足道的:
但是等等,如果橙色矩形不与蓝色矩形重叠,那么你就会遇到问题:
在这个例子中,我们的重叠区域得到了 -850,这是不对的。更糟糕的是,如果检测不与任一维度重叠(不在 x 轴或 y 轴上),那么您仍然会得到一个正数,因为 两个 维度都是负数。这就是为什么您将Max(0, ...) * Max(0, ...) 视为解决方案的一部分的原因;它确保如果任何重叠为负,您将从您的函数中获得 0。
与我们的符号系统保持一致的最终公式:
值得注意的是,可能不需要使用max(0, ...) 函数。您可能想知道某些东西是否沿其一个维度而不是所有维度重叠;如果您使用 max 那么您将删除该信息。出于这个原因,请考虑如何处理非重叠边界框。通常,max 函数很好用,但值得注意的是它在做什么。
最后,请注意,由于此比较仅涉及线性测量,因此可以缩放到任意尺寸或任意重叠的四边形。
总结一下:
intersecting_area =
max(0, min(orange.circle.x, blue.circle.x)
- max(orange.triangle.x, blue.triangle.x))
* max(0, min(orange.circle.y, blue.circle.y)
- max(orange.triangle.y, blue.triangle.y)
)
percent_coverage = intersecting_area
/ (orange_area + blue_area - intersecting_area)