确定线是否与CGRect相交

时间:2013-07-19 21:30:07

标签: graphics core-graphics

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

我正在寻找类似的东西:

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
}

3 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:1)

对于任何使用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)));
}

答案 2 :(得分:0)

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)))
    }
}