How to test if a line segment intersects an axis-aligned rectange in 2D?

前端 未结 12 733
执念已碎
执念已碎 2020-11-30 07:33

How to test if a line segment intersects an axis-aligned rectange in 2D? The segment is defined with its two ends: p1, p2. The rectangle is defined with top-left and bottom-

相关标签:
12条回答
  • 2020-11-30 07:58

    The original poster wanted to DETECT an intersection between a line segment and a polygon. There was no need to LOCATE the intersection, if there is one. If that's how you meant it, you can do less work than Liang-Barsky or Cohen-Sutherland:

    Let the segment endpoints be p1=(x1 y1) and p2=(x2 y2).
    Let the rectangle's corners be (xBL yBL) and (xTR yTR).

    Then all you have to do is

    A. Check if all four corners of the rectangle are on the same side of the line. The implicit equation for a line through p1 and p2 is:

    F(x y) = (y2-y1)*x + (x1-x2)*y + (x2*y1-x1*y2)

    If F(x y) = 0, (x y) is ON the line.
    If F(x y) > 0, (x y) is "above" the line.
    If F(x y) < 0, (x y) is "below" the line.

    Substitute all four corners into F(x y). If they're all negative or all positive, there is no intersection. If some are positive and some negative, go to step B.

    B. Project the endpoint onto the x axis, and check if the segment's shadow intersects the polygon's shadow. Repeat on the y axis:

    If (x1 > xTR and x2 > xTR), no intersection (line is to right of rectangle).
    If (x1 < xBL and x2 < xBL), no intersection (line is to left of rectangle).
    If (y1 > yTR and y2 > yTR), no intersection (line is above rectangle).
    If (y1 < yBL and y2 < yBL), no intersection (line is below rectangle).
    else, there is an intersection. Do Cohen-Sutherland or whatever code was mentioned in the other answers to your question.

    You can, of course, do B first, then A.

    Alejo

    0 讨论(0)
  • 2020-11-30 07:59

    I did a little napkin solution..

    Next find m and c and hence the equation y = mx + c

    y = (Point2.Y - Point1.Y) / (Point2.X - Point1.X)
    

    Substitute P1 co-ordinates to now find c

    Now for a rectangle vertex, put the X value in the line equation, get the Y value and see if the Y value lies in the rectangle bounds shown below

    (you can find the constant values X1, X2, Y1, Y2 for the rectangle such that)

    X1 <= x <= X2 & 
    Y1 <= y <= Y2
    

    If the Y value satisfies the above condition and lies between (Point1.Y, Point2.Y) - we have an intersection. Try every vertex if this one fails to make the cut.

    0 讨论(0)
  • 2020-11-30 08:01

    Since your rectangle is aligned, Liang-Barsky might be a good solution. It is faster than Cohen-Sutherland, if speed is significant here.

    Siggraph explanation
    Another good description
    And of course, Wikipedia

    0 讨论(0)
  • 2020-11-30 08:02

    coding example in PHP (I'm using an object model that has methods for things like getLeft(), getRight(), getTop(), getBottom() to get the outer coordinates of a polygon and also has a getWidth() and getHeight() - depending on what parameters were fed it, it will calculate and cache the unknowns - i.e. I can create a polygon with x1,y1 and ... w,h or x2,y2 and it can calculate the others)

    I use 'n' to designate the 'new' item being checked for overlap ($nItem is an instance of my polygon object) - the items to be tested again [this is a bin/sort knapsack program] are in an array consisting of more instances of the (same) polygon object.

    public function checkForOverlaps(BinPack_Polygon $nItem) {
      // grab some local variables for the stuff re-used over and over in loop
      $nX = $nItem->getLeft();
      $nY = $nItem->getTop();
      $nW = $nItem->getWidth();
      $nH = $nItem->getHeight();
      // loop through the stored polygons checking for overlaps
      foreach($this->packed as $_i => $pI) {
        if(((($pI->getLeft()  - $nW) < $nX) && ($nX < $pI->getRight())) &&
           ((($pI->getTop()  - $nH) < $nY) && ($nY < $pI->getBottom()))) {
          return false;
        }
      }
      return true;
    }
    
    0 讨论(0)
  • 2020-11-30 08:04

    Use the Cohen-Sutherland algorithm.

    It's used for clipping but can be slightly tweaked for this task. It divides 2D space up into a tic-tac-toe board with your rectangle as the "center square".
    then it checks to see which of the nine regions each of your line's two points are in.

    • If both points are left, right, top, or bottom, you trivially reject.
    • If either point is inside, you trivially accept.
    • In the rare remaining cases you can do the math to intersect with whichever sides of the rectangle are possible to intersect with, based on which regions they're in.
    0 讨论(0)
  • 2020-11-30 08:05

    Some sample code for my solution (in php):

    // returns 'true' on overlap checking against an array of similar objects in $this->packed
    public function checkForOverlaps(BinPack_Polygon $nItem) {
      $nX = $nItem->getLeft();
      $nY = $nItem->getTop();
      $nW = $nItem->getWidth();
      $nH = $nItem->getHeight();
      // loop through the stored polygons checking for overlaps
      foreach($this->packed as $_i => $pI) {
        if(((($pI->getLeft() - $nW) < $nX) && ($nX < $pI->getRight())) && ((($pI->getTop() - $nH) < $nY) && ($nY < $pI->getBottom()))) {
          return true;
        }
      }
      return false;
    }
    
    0 讨论(0)
提交回复
热议问题