如何计算点和与轴对齐的矩形之间的距离?


29

我有一个带有x,y位置,高度和宽度的2D矩形,并且附近有一个随机定位的点。

有没有一种方法可以检查如果该点比一定距离更近,则该点是否可能与矩形碰撞?想象一下该点之外的不可见半径与所述矩形碰撞。我有一个问题,仅仅是因为它不是正方形!

Answers:


26

如果(x,y)是矩形的中心,则(px,py)可以通过以下方式计算从点到矩形边界的平方距离:

dx = max(abs(px - x) - width / 2, 0);
dy = max(abs(py - y) - height / 2, 0);
return dx * dx + dy * dy;

如果该平方距离为零,则表示该点触摸矩形或位于矩形内部。


6
对于任何其他想知道的人,(x,y)是矩形的中心,而不是角
Greg Rozmarynowycz 2014年

2
对不起,我的评论很旧,但是这个方程式是否假设矩形是轴对齐的?
BitNinja 2014年

1
@BitNinja是的,这就是问题所在。如果它不是轴对齐的,最快/最简单的算法将取决于矩形信息的存储方式。
sam hocevar,2014年

例如,点为(4:4),矩形为(5:5),宽/高(5:5)。您的代码将声称该点接触或在矩形内部,但显然在矩形外部
LRN

@LRN以(5:5)为中心,宽/高(5:5)的矩形从(2.5:2.5)到(7.5:7.5)。点(4:4)在该矩形内。
sam hocevar

11

我假设您的矩形是Axis-Aligned。

您只需要将点“夹紧”到矩形中,然后计算到夹紧点的距离即可。

点=(px,py),矩形=(rx,ry,rwidth,高度)//(左上角,尺寸)

function pointRectDist (px, py, rx, ry, rwidth, rheight)
{
    var cx = Math.max(Math.min(px, rx+rwidth ), rx);
    var cy = Math.max(Math.min(py, ry+rheight), ry);
    return Math.sqrt( (px-cx)*(px-cx) + (py-cy)*(py-cy) );
}

3

为此,必须使用圆角矩形碰撞。关于堆栈溢出也有类似的问题。

圆的中心将成为问题点,半径将是您要检查的距离。


3

如果要计算从点到矩形边缘的距离,则使用矩形创建的九个区域中的每个区域可能是最快的方法:

function pointRectangleDistance(x, y, x1, y1, x2, y2) {
    var dx, dy;
    if (x < x1) {
        dx = x1 - x;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else if (x > x2) {
        dx = x - x2;
        if (y < y1) {
            dy = y1 - y;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else if (y > y2) {
            dy = y - y2;
            return Math.sqrt(dx * dx + dy * dy);
        }
        else {
            return dx;
        }
    }
    else {
        if (y < y1) {
            return y1 - y;
        }
        else if (y > y2) {
            return y - y2;
        }
        else {
            return 0.0; // inside the rectangle or on the edge
        }
    }
}

2

[根据评论修改答案]

如果要查看下图的灰色矩形是否在10个单位内,请检查该点是否位于

  1. 红色矩形
  2. 蓝色矩形
  3. 任一绿色圆圈(半径10)

在此处输入图片说明

inside=false;

bluerect.x=oldrect.x-10;
bluerect.y=oldrect.y;
bluerect.width=oldrect.width;
bluerect.height=oldrect.height+20;

if(  point.x >=bluerect && point.x <=redrect.x+bluerect.width &&
     point.y >=bluerect && point.y <=redrect.y+bluerect.height){
         //now point is side the blue rectangle
         inside=true;
}

redrect.x=oldrect.x;
redrect.y=oldrect.y-10;
redrect.width=oldrect.width+20;
redrect.height=oldrect.height;

if(  point.x >=redrect&& point.x <=redrect.x+redrect.width &&
     point.y >=redrect&& point.y <=redrect.y+redrect.height){
         //now point is side the redrectangle
         inside=true;
}


d1= distance(point, new point(oldrect.x, oldrect.y)) //calculate distance between point and (oldrect.x, oldrect.y)
d2= distance(point, new point(oldrect.x+10, oldrect.y))
d3= distance(point, new point(oldrect.x, oldrect.y+10))
d4= distance(point, new point(oldrect.x+10, oldrect.y+10))
if (d1 < 10 || d2 <10 || d3 < 10 || d4 <10){
    inside=true;
}

//inside is now true if the point is within 10 units of rectangle

这种方法有点不雅致。在stackoverflow上记录了一种类似的方法,该方法避免了必须使用矩形对称性来测试所有4个角的情况


在对角线方向上,这将给例如的点带来误报。11个单位远。
埃里克B

更新的图片显然是错误的,实际上它实际上说明了错误情况并使其看起来正确。这个绿点很容易就可以超过10个单位,并位于该外部矩形内。
Eric B

嘿@EricB,我已修复您指出的错误,如何撤消您的降票?

您的回答将不再给出严格错误的结果,因此我删除了弃权票,但这也不是最好的方法。为什么不仅仅测试一下中心是否在矩形内以及四个线段是否与圆相交呢?这些新的矩形和圆形的构造只是不必要的。您的答案也没有提供从点到矩形的实际距离。
埃里克B

老实说,这个答案太糟糕了。12个附加项,4个对象构造,12个测试,4个平方根的任务实际上需要3行代码?
sam hocevar

-2

您可以使用如下形式: 在此处输入图片说明


这种方法似乎不必要地复杂。查找x1和y1对于解决此问题不是必需的。
埃里克B

实际上,这甚至不能满足在给定距离内找到碰撞的要求。这只是检测点是否在矩形内的一种不好的方法。
埃里克B

距离的度量已经隐式存在。if(d2 <10 * 10){/ *在10个测量单位内* /}
AlexanderBrevig
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.