如何识别2D中2个矩形之间重叠区域的边界点?

时间:2011-08-07 20:19:03

标签: algorithm computational-geometry intersection

我希望返回2D中2个任意矩形之间重叠区域的点的坐标。什么是解决所有特殊情况的最佳方法,例如:

  • 仅在单个顶点上相交的矩形? (程序必须返回单独的顶点)
  • 共享整个或部分边的矩形? (程序必须返回公共线段的端点)

为了增加复杂性,它必须以顺时针/逆时针顺序对点进行排序。因此,我可以使用凸包算法在报告之前对它们进行排序,但是如果有一个算法可以直接找出边界点,那将是最好的!

我应该关注哪些方面的想法?我不是在寻找代码项目等,只是对通用算法的一般概念,我不需要保留很多 if "special case" then "do this"种代码。

编辑:矩形是任意的 - 即它们可能/可能不平行于X / Y轴......

5 个答案:

答案 0 :(得分:1)

只需使用一般凸多边形交叉法。查看intersect convex polygons rotating calipers

答案 1 :(得分:1)

好的,我们会再试一次......

考虑两者的结合,由通过从ABCD(黑色)中的每个顶点绘制一条线到EFGH(红色)定义的区域组成:

enter image description here

这里的难点是这些线所定义的所有形状(灰线和来自ABCD和EFGH矩形的原始线)。

一旦弄明白,就创建一个这些形状的链表,并假设这些形状中的每一个都存在于交叉点内。

第1步。翻译&旋转所有内容,使ABCD在0,0上有一个顶点,其线与x和y轴平行/垂直。

步骤1A。在ABCD中找到最低的y值顶点,然后从场景中的所有其他顶点中减去它。让我们假设为了证明该顶点是C.通过从场景中的每个顶点减去C,我们将有效地将原点(0,0)移动到C,使C周围的旋转变得容易。

for all shapes in linked list {
    for all vertices in shape {
        vertex -= C;
    }
}

步骤1B。将原点的所有内容旋转一个等于C-> B矢量和x轴之间角度的角度,使B落在x轴上:< / p>

// see http://en.wikipedia.org/wiki/Atan2
float rotRadians = atan2(B.x, B.y);  // assuming ABCD vertices are labelled clockwise

for all shapes in linked list {
    for all vertices in shape {
        rot(thisVert, rotRadians);
    }
}


// ...

// function declaration
void rot(theVertex, theta) {
    tempX = theVertex.x;
    tempY = theVertex.y;

    theVertex.x = cos(theta) * tempX + sin(theta) * tempY;
    theVertex.y = cos(theta) * tempY - sin(theta) * tempX;

}

如果顺时针标记ABCD顶点,则ABCD顶点现在应如下所示:

A = ABCDx , ABCDy
B = ABCDx ,   0
C = 0     ,   0
D = 0     , ABCDy

(如果它们没有顺时针标记,则步骤2中的“搁置”检查将不起作用,因此请确保atan2(...)调用中使用的顶点是从最低顶点逆时针旋转的顶点。)

第2步。现在,我们可以轻松分析形状是否位于ABCD矩形内,例如: if (thisVert.x >= 0 && thisVert.y >= 0 && thisVert.x <= ABCDx && thisVert.y <= ABCDy)。遍历形状的链接列表,并检查以确保每个形状的每个顶点位于ABCD内。如果形状的一个顶点不在ABCD内,那么该形状不是ABCD / EFGH交点的一部分。将其标记为不是交叉点的一部分并跳到下一个形状。

第3步。撤消步骤1B中的轮换,然后撤消步骤1A中的翻译。

步骤4。使用EFGH而不是ABCD重复步骤1-3,您将设置交集。


如果两个集合之间的唯一交集是一条线,那么上面的内容将不会返回任何交集。如果交集== NULL,则检查相交的行。

如果交点仍为NULL,则检查交叉点。

答案 2 :(得分:0)

这可能非常粗糙,但是:

object rectangle { 

     pos  { x, y }              // top-left position
     size { height, width }     // rectangle-size
}


collision::check (rectangle rect) {

     // collision-detection logic 

     collision->order_coords(coords);   // order-coords clockwise;
     return collision_result_object;    // return collided vertices, ordered clockwise, or 0 if rect hit nothing
}

collision::order_rects (rectangle *rect, opt angle)  {

     return clockwise_rects; // returns rectangles ordered clockwise
}

collision::order_coords (coordinate *coord, opt angle) {

     return ordered_coords; // recieves coordinates and returns ordered clockwise
}

rectangle rects; // bunch of rectangles

ordered_rects = collision->order_rects (rects); // order rects starting at 12PM

loop {    

       foreach ordered_rects as i {

           if (collision->check(i)) {

           array_of_collision_result_objects[i] = collision->check(i);      // start checking rects starting at 12PM, if collision found, return ordered vertexes
           }
       }

}

答案 3 :(得分:0)

找到矩形段的所有交叉点。结果由一些和一些初始顶点组成。要找到它们,只需检查它们在两个矩形中的每个点。删除不必要的点(如果一行中有3个或更多)。结果是凸的,你得到的任何一点都不是严格的内部,所以(如果至少有3个)从一些内部逐点角度排序点并享受结果。

答案 4 :(得分:0)

我想出了一个合理的方法,应该涵盖所有可能的情况:

我们所需要的只是基本步骤:

第1步:

for each side Si of R1
    for each side Sj of R2
           Check if Si and Sj intersect. If they do, push the point in results array
           (This also has to take care of the case in case Si and Sj overlap, which is 
           basically checking if they  have the same equation or not - if so, push in 
           the points of overlap. This also takes care of the case where a vertex of 
           R2 lies on Si).
    next
next

第2步:

for each vertex Vi of R1
   Check if Vi lies inside R2, If so, push it in the results array.
next

第3步:

for each vertex Vi of R2
   Check if Vi lies inside R1, If so, push it in the results array.
next

现在,订购结果数组,然后返回

对于第2步&amp; 3(如何找到一个点是否位于矩形内) - 我使用this excellent article(那里所说的最后一个算法)。