简体   繁体   English

找出点是否位于矩形内

[英]Find if point lies within a rectangle

如何找到一个点位于给定4个点的2D矩形内?

Transform the point to a coordinate frame aligned with the rectangle, then the problem becomes axis-aligned and trivial. 将点转换为与矩形对齐的坐标框,然后问题变得轴对齐且无关紧要。

If the rectangle consists of the following 4 points: 如果矩形包含以下4点:

a  b
c  d

Then get the "x-axis" and "y-axis" of the rectangle as: 然后得到矩形的“x轴”和“y轴”:

x = Normalize(d-c)
y = Normalize(a-c)

Then construct a rotation matrix using x and y as columns: 然后使用x和y作为列构造旋转矩阵:

r = [ x | y ]

If you're using 3-d coordinates, we need az axis: 如果你使用三维坐标,我们需要az轴:

z = CrossProduct(x, y)
r = [ x | y | z ]

Your transform matrix from world coordinates to your rectangle's axis-aligned coordinates becomes: 从世界坐标到矩形轴对齐坐标的变换矩阵变为:

T = [ r^T | -r^T * c ]
    [ 0^T |     1    ]

Here we've chosen the lower-left corner c to be the local origin. 在这里,我们选择了左下角c作为本地原点。 "r^T" is r transposed. “r ^ T”被转置。 "0^T" is either a 2-d or 3-d row-vector filled with zeros. “0 ^ T”是用零填充的2-d或3-d行向量。 1 is just a one. 1只是一个。 Note that this is just the inverse of the simpler rectangle-to-world transform, which is 请注意,这只是简单的矩形到世界变换的反转,即

T^-1 = [ r   | c ]
       [ 0^T | 1 ]

We can use T to transform the point to axis-aligned coordinates. 我们可以使用T将点转换为轴对齐坐标。 Remember to pad p with a trailing 1, since T is a homogeneous matrix. 记得用尾随1填充p,因为T是一个齐次矩阵。

tp = T * p;  // Don't forget to pad p with a trailing 1 before multiplying.

// Checks that p isn't below or to the left of the rectangle.
for ( int d = 0; d < num_dimensions; ++d ) {
  if ( tp[d] < 0.0 ) {
    return false;
  }
}

// Checks that p isn't to the right of the rectangle
double width = Length(d-c);
if ( tp[0] > width ) {
  return false;
}

// Checks that p isn't above the rectangle.
double height = Length(a-c);
if ( tp[1] > height ) {
  return false;
}

// p must be inside or on the rectangle.
return true

If you're using 3d coordinates, note that the above disregards the local z value of transformed point tp. 如果您正在使用3d坐标,请注意上面忽略了转换点tp的局部z值。 Even if p is out of the plane of the rectangle, the above behaves as if it's been projected to the rectangle surface. 即使p在矩形的平面之外,上面的行为就好像它被投影到矩形表面一样。 If you want to check for coplanarity, just do the following beforehand: 如果要检查共面性,请事先执行以下操作:

if ( fabs(tp[2]) > some_small_positive_number ) {
   return false;  // point is out of the rectangle's plane.
}

I think this might answer your question 我想这可能会回答你的问题

  • full disclosure - I went to Drexel for my grad dregree 完全披露 - 我去了Drexel为我的毕业生

To make it OpenGl specific: 为了使OpenGl具体化:

I suppose your 2D rectangle is in screen coordinates! 我想你的2D矩形在屏幕坐标中!

first: 第一:

 gluProject (bli, bla, blorp, ...);

to get from 3d to screen coordinates. 从3d到屏幕坐标。

Then: Noah's suggestion. 然后:诺亚的建议。

Only shoot yourself if your point in question is already 2D ;) 如果您的问题已经是2D,请仅拍摄自己;)

For a non-axis-aligned rectangle, use the same algorithm as for general polygons: the point-in-polygon test: 对于非轴对齐的矩形,使用与一般多边形相同的算法:多边形点测试:

Imagine a ray pointing rightward from the test point. 想象一下从测试点向右指向的光线。 Test whether each line in the polygon crosses the ray. 测试多边形中的每条线是否穿过光线。 If an even number of lines crosses the ray, then the point is outside the polygon. 如果偶数行穿过光线,则该点位于多边形外部。 If an odd number of lines crosses the ray, then the point is inside the polygon. 如果奇数行与光线相交,则该点在多边形内。

In the case of a rectangle, between zero and two lines will cross the ray. 在矩形的情况下,零和两条线之间将穿过光线。

If a line touches the ray but does not cross it, the result is ambiguous. 如果一条线接触光线但没有穿过它,结果就不明确了。 Therefore, in your calculations, imagine that the ray is an infinitely small amount ɛ higher than its y coordinate, so that it is impossible for a line to touch the ray without crossing it. 因此,在你的计算中,想象一下光线的数量是无限小的ɛ,高于它的y坐标,这样一条线就不可能在不穿过光线的情况下触摸光线。

Given your test point (x,y) and line (x1,y1,x2,y2), testing whether a line crosses the ray is pretty simple. 给定测试点(x,y)和线(x1,y1,x2,y2),测试线是否穿过光线非常简单。 Assume, without loss of generality, that y1 < y2. 假设,在不失一般性的情况下,y1 <y2。 Then 然后

if y < y2 and y >= y1:
    let x0 = x1 + (y-y1)/(y2-y1) * (x2-x1) // crossing point (x0,y)
    if x0 > x:
        crossing_detected++

http://en.wikipedia.org/wiki/Point_in_polygon http://en.wikipedia.org/wiki/Point_in_polygon

It's easy to test if a point lies in a triangle, so you can split your rectangle in two triangles and test these. 如果一个点位于三角形中,则很容易测试,因此您可以将矩形分成两个三角形并进行测试。 See eg http://www.blackpawn.com/texts/pointinpoly/default.html 参见例如http://www.blackpawn.com/texts/pointinpoly/default.html

Generic test for point in quadrilateral is sufficient. 四边形点的通用测试就足够了。 The quad is defined as an ordered series of points. 四边形被定义为一系列有序的点。 Handles both clockwise and counter-clockwise winding: 顺时针和逆时针缠绕:

typedef struct {float x; float y} vec2;
bool pointIsInQuad(const vec2 point, const vec2 quad[4])
{
    bool sides[4];
    for (int i = 0; i < 4; i++) {
        sides[i] = ((point.x - quad[i].x)*(quad[(i + 1)%4].y - quad[i].y) - (point.y - quad[i].y)*(quad[(i + 1)%4].x - quad[i].x)) > 0.0f;
    }
    return ((sides[0] == sides[1]) && (sides[0] == sides[2]) && (sides[0] == sides[3]));
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM