【问题标题】:Determine if line intersects CGRect确定线是否与 CGRect 相交
【发布时间】:2013-07-19 21:30:06
【问题描述】:

确定直线是否与矩形相交最有效的方法是什么?

我正在寻找类似的东西:

CGPoint startLine = CGPointMake(5.0f,5.0f);
CGPoint endLine = CGPointMake(25.0f,25.0f);

CGRect intersectingRect = CGRectMake(10.0f,10.0f,50.0f,50.0f);

if (CGRectContainsLine(intersectingRect,startLine,endLine)) { //true
    //line intersects rectangle
}

【问题讨论】:

    标签: graphics core-graphics


    【解决方案1】:

    没有内置任何东西,但应该这样做:

    BOOL RectContainsLine(CGRect r, CGPoint lineStart, CGPoint lineEnd)
    {
        BOOL (^LineIntersectsLine)(CGPoint, CGPoint, CGPoint, CGPoint) = ^BOOL(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End)
        {
            CGFloat q =
                //Distance between the lines' starting rows times line2's horizontal length
                (line1Start.y - line2Start.y) * (line2End.x - line2Start.x)
                //Distance between the lines' starting columns times line2's vertical length
                - (line1Start.x - line2Start.x) * (line2End.y - line2Start.y);
            CGFloat d =
                //Line 1's horizontal length times line 2's vertical length
                (line1End.x - line1Start.x) * (line2End.y - line2Start.y)
                //Line 1's vertical length times line 2's horizontal length
                - (line1End.y - line1Start.y) * (line2End.x - line2Start.x);
    
            if( d == 0 )
                return NO;
    
            CGFloat r = q / d;
    
            q =
                //Distance between the lines' starting rows times line 1's horizontal length
                (line1Start.y - line2Start.y) * (line1End.x - line1Start.x)
                //Distance between the lines' starting columns times line 1's vertical length
                - (line1Start.x - line2Start.x) * (line1End.y - line1Start.y);
    
            CGFloat s = q / d;
            if( r < 0 || r > 1 || s < 0 || s > 1 )
                return NO;
    
            return YES;
        };
    
        /*Test whether the line intersects any of:
         *- the bottom edge of the rectangle
         *- the right edge of the rectangle
         *- the top edge of the rectangle
         *- the left edge of the rectangle
         *- the interior of the rectangle (both points inside)
         */
    
        return (LineIntersectsLine(lineStart, lineEnd, CGPointMake(r.origin.x, r.origin.y), CGPointMake(r.origin.x + r.size.width, r.origin.y)) ||
                LineIntersectsLine(lineStart, lineEnd, CGPointMake(r.origin.x + r.size.width, r.origin.y), CGPointMake(r.origin.x + r.size.width, r.origin.y + r.size.height)) ||
                LineIntersectsLine(lineStart, lineEnd, CGPointMake(r.origin.x + r.size.width, r.origin.y + r.size.height), CGPointMake(r.origin.x, r.origin.y + r.size.height)) ||
                LineIntersectsLine(lineStart, lineEnd, CGPointMake(r.origin.x, r.origin.y + r.size.height), CGPointMake(r.origin.x, r.origin.y)) ||
                (CGRectContainsPoint(r, lineStart) && CGRectContainsPoint(r, lineEnd)));
    }
    

    从这个问题简单移植:How to know if a line intersects a rectangle

    【讨论】:

    • 对 Peter Hosey 的说明性 cmets 大赞!谢谢。
    【解决方案2】:

    对于任何使用 Objective-c 的人:

    - (BOOL)rectContainsLine:(CGRect)rect startPoint:(CGPoint)lineStart endPoint:(CGPoint)lineEnd {
    BOOL (^LineIntersectsLine)(CGPoint, CGPoint, CGPoint, CGPoint) = ^BOOL(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
    
        CGFloat q =
        //Distance between the lines' starting rows times line2's horizontal length
        (line1Start.y - line2Start.y) * (line2End.x - line2Start.x)
        //Distance between the lines' starting columns times line2's vertical length
        - (line1Start.x - line2Start.x) * (line2End.y - line2Start.y);
        CGFloat d =
        //Line 1's horizontal length times line 2's vertical length
        (line1End.x - line1Start.x) * (line2End.y - line2Start.y)
        //Line 1's vertical length times line 2's horizontal length
        - (line1End.y - line1Start.y) * (line2End.x - line2Start.x);
    
        if( d == 0 )
            return NO;
    
        CGFloat r = q / d;
    
        q =
        //Distance between the lines' starting rows times line 1's horizontal length
        (line1Start.y - line2Start.y) * (line1End.x - line1Start.x)
        //Distance between the lines' starting columns times line 1's vertical length
        - (line1Start.x - line2Start.x) * (line1End.y - line1Start.y);
    
        CGFloat s = q / d;
        if( r < 0 || r > 1 || s < 0 || s > 1 )
            return NO;
    
        return YES;
    };
    
    /*Test whether the line intersects any of:
     *- the bottom edge of the rectangle
     *- the right edge of the rectangle
     *- the top edge of the rectangle
     *- the left edge of the rectangle
     *- the interior of the rectangle (both points inside)
     */
    
    return (LineIntersectsLine(lineStart, lineEnd, CGPointMake(rect.origin.x, rect.origin.y), CGPointMake(rect.origin.x + rect.size.width, rect.origin.y)) ||
            LineIntersectsLine(lineStart, lineEnd, CGPointMake(rect.origin.x + rect.size.width, rect.origin.y), CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height)) ||
            LineIntersectsLine(lineStart, lineEnd, CGPointMake(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height), CGPointMake(rect.origin.x, rect.origin.y + rect.size.height)) ||
            LineIntersectsLine(lineStart, lineEnd, CGPointMake(rect.origin.x, rect.origin.y + rect.size.height), CGPointMake(rect.origin.x, rect.origin.y)) ||
            (CGRectContainsPoint(rect, lineStart) && CGRectContainsPoint(rect, lineEnd)));
    }
    

    【讨论】:

      【解决方案3】:

      Swift 版本:

      extension CGRect {
          private func lineIntersectsLine(_ line1Start: CGPoint, _ line1End: CGPoint, _ line2Start: CGPoint, _ line2End: CGPoint) -> Bool {
              // Distance between the lines' starting rows times line2's horizontal length
              var q = (line1Start.y - line2Start.y) * (line2End.x - line2Start.x)
                  //Distance between the lines' starting columns times line2's vertical length
                  - (line1Start.x - line2Start.x) * (line2End.y - line2Start.y)
              let d =
              //Line 1's horizontal length times line 2's vertical length
              (line1End.x - line1Start.x) * (line2End.y - line2Start.y)
              //Line 1's vertical length times line 2's horizontal length
              - (line1End.y - line1Start.y) * (line2End.x - line2Start.x)
      
              if d == 0 {
                  return false
              }
      
              let r = q / d
      
              q =
                  //Distance between the lines' starting rows times line 1's horizontal length
                  (line1Start.y - line2Start.y) * (line1End.x - line1Start.x)
                  //Distance between the lines' starting columns times line 1's vertical length
                  - (line1Start.x - line2Start.x) * (line1End.y - line1Start.y);
      
              let s = q / d
              if r < 0 || r > 1 || s < 0 || s > 1 {
                  return false
              }
      
              return true
          }
      
      
          func instersectsLine(start lineStart: CGPoint, end lineEnd: CGPoint) -> Bool
          {
              /*Test whether the line intersects any of:
               *- the bottom edge of the rectangle
               *- the right edge of the rectangle
               *- the top edge of the rectangle
               *- the left edge of the rectangle
               *- the interior of the rectangle (both points inside)
               */
              return (lineIntersectsLine(lineStart, lineEnd, CGPoint(x:self.origin.x, y: self.origin.y), CGPoint(x: self.origin.x + self.size.width, y: self.origin.y)) ||
                  lineIntersectsLine(lineStart, lineEnd, CGPoint(x: self.origin.x + self.size.width, y: self.origin.y), CGPoint(x: self.origin.x + self.size.width, y: self.origin.y + self.size.height)) ||
                  lineIntersectsLine(lineStart, lineEnd, CGPoint(x: self.origin.x + self.size.width, y: self.origin.y + self.size.height), CGPoint(x: self.origin.x, y: self.origin.y + self.size.height)) ||
                  lineIntersectsLine(lineStart, lineEnd, CGPoint(x: self.origin.x, y: self.origin.y + self.size.height), CGPoint(x: self.origin.x, y: self.origin.y)) ||
                  (contains(lineStart) && contains(lineEnd)))
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多