坐标中两条线之间的交点

问题描述 投票:6回答:5

我可以检测到两条线的交点,但是如果我的线没有我的屏幕的长度,它会检测到它不应该在的点。

这里是预览:因此,它不应该检测到这个交叉点,因为水平线不是那么长。

码:

- (NSMutableArray *) intersectWithLines:(CGPoint)startPoint andEnd:(CGPoint)endPoint {
    NSMutableArray *intersects = [[NSMutableArray alloc] init];

    for(GameLine *line in [_lineBackground getLines]) {

        double lineStartX = line.startPos.x;
        double lineStartY = line.startPos.y;
        double tempEndX = line.endPos.x;
        double tempEndY = line.endPos.y;

        double d = ((startPoint.x - endPoint.x)*(lineStartY - tempEndY)) - ((startPoint.y - endPoint.y) * (lineStartX - tempEndX));

        if(d != 0) {            
            double sX = ((lineStartX - tempEndX) * (startPoint.x * endPoint.y - startPoint.y * endPoint.x) - (startPoint.x - endPoint.x) * (lineStartX * tempEndY - lineStartY * tempEndX)) / d;
            double sY = ((lineStartY - tempEndY) * (startPoint.x * endPoint.y - startPoint.y * endPoint.x) - (startPoint.y - endPoint.y) * (lineStartX * tempEndY - lineStartY * tempEndX)) / d;


            if([self isValidCGPoint:CGPointMake(sX, sY)]) {
                [intersects addObject:[NSValue valueWithCGPoint:CGPointMake(sX, sY)]];
            }            
        }
    }

    return intersects;
}
iphone objective-c math 2d intersection
5个回答
29
投票

如果我正确理解您的问题,您需要确定两个线段的交点。这应该使用以下方法:

- (NSValue *)intersectionOfLineFrom:(CGPoint)p1 to:(CGPoint)p2 withLineFrom:(CGPoint)p3 to:(CGPoint)p4
{
    CGFloat d = (p2.x - p1.x)*(p4.y - p3.y) - (p2.y - p1.y)*(p4.x - p3.x);
    if (d == 0)
        return nil; // parallel lines
    CGFloat u = ((p3.x - p1.x)*(p4.y - p3.y) - (p3.y - p1.y)*(p4.x - p3.x))/d;
    CGFloat v = ((p3.x - p1.x)*(p2.y - p1.y) - (p3.y - p1.y)*(p2.x - p1.x))/d;
    if (u < 0.0 || u > 1.0)
        return nil; // intersection point not between p1 and p2
    if (v < 0.0 || v > 1.0)
        return nil; // intersection point not between p3 and p4
    CGPoint intersection;
    intersection.x = p1.x + u * (p2.x - p1.x);
    intersection.y = p1.y + u * (p2.y - p1.y);

    return [NSValue valueWithCGPoint:intersection];
}

6
投票

这是Hayden Holligan's answer的略微修改版本,可与Swift 3一起使用:

func getIntersectionOfLines(line1: (a: CGPoint, b: CGPoint), line2: (a: CGPoint, b: CGPoint)) -> CGPoint {

    let distance = (line1.b.x - line1.a.x) * (line2.b.y - line2.a.y) - (line1.b.y - line1.a.y) * (line2.b.x - line2.a.x)
    if distance == 0 {
        print("error, parallel lines")
        return CGPoint.zero
    }

    let u = ((line2.a.x - line1.a.x) * (line2.b.y - line2.a.y) - (line2.a.y - line1.a.y) * (line2.b.x - line2.a.x)) / distance
    let v = ((line2.a.x - line1.a.x) * (line1.b.y - line1.a.y) - (line2.a.y - line1.a.y) * (line1.b.x - line1.a.x)) / distance

    if (u < 0.0 || u > 1.0) {
        print("error, intersection not inside line1")
        return CGPoint.zero
    }
    if (v < 0.0 || v > 1.0) {
        print("error, intersection not inside line2")
        return CGPoint.zero
    }

    return CGPoint(x: line1.a.x + u * (line1.b.x - line1.a.x), y: line1.a.y + u * (line1.b.y - line1.a.y))
}

3
投票

Swift版本

func getIntersectionOfLines(line1: (a: CGPoint, b: CGPoint), line2: (a: CGPoint, b: CGPoint)) -> CGPoint {
        let distance = (line1.b.x - line1.a.x) * (line2.b.y - line2.a.y) - (line1.b.y - line1.a.y) * (line2.b.x - line2.a.x)
        if distance == 0 {
            print("error, parallel lines")
            return CGPointZero
        }

        let u = ((line2.a.x - line1.a.x) * (line2.b.y - line2.a.y) - (line2.a.y - line1.a.y) * (line2.b.x - line2.a.x)) / distance
        let v = ((line2.a.x - line1.a.x) * (line1.b.y - line1.a.y) - (line2.a.y - line1.a.y) * (line1.b.x - line1.a.x)) / distance

        if (u < 0.0 || u > 1.0) {
            print("error, intersection not inside line1")
            return CGPointZero
        }
        if (v < 0.0 || v > 1.0) {
            print("error, intersection not inside line2")
            return CGPointZero
        }

        return CGPointMake(line1.a.x + u * (line1.b.x - line1.a.x), line1.a.y + u * (line1.b.y - line1.a.y))
    }

2
投票

这是正确的等式:

+(CGPoint) intersection2:(CGPoint)u1 u2:(CGPoint)u2 v1:(CGPoint)v1 v2:(CGPoint)v2 {  
    CGPoint ret=u1;  
    double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))  
    /((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));  
    ret.x+=(u2.x-u1.x)*t;  
    ret.y+=(u2.y-u1.y)*t;  
    return ret;  
}  

此外,您可以检查此库以计算线交叉:http://www.cprogramdevelop.com/5045485/


1
投票

这是Swift 4.2中的另一个解决方案。这在功能上与MartinR的解决方案相同,但使用simd向量和矩阵来清理它。

/// Protocol adoped by any type that models a line segment.
protocol LineSegment
{
    /// Point defining an end of a line segment.
    var p1: simd_double2 { get }
    /// Point defining an end of a line segment.
    var p2: simd_double2 { get }
}

extension LineSegment
{
    /// Calcualte the intersection between this line segment and another line
    /// segment.
    ///
    /// Algorithm from here:
    /// http://www.cs.swan.ac.uk/~cssimon/line_intersection.html
    ///
    /// - Parameter other: The other line segment.
    /// - Returns: The intersection point, or `nil` if the two line segments are
    ///            parallel or the intersection point would be off the end of
    ///            one of the line segments.
    func intersection(lineSegment other: LineSegment) -> simd_double2?
    {
        let p3 = other.p1 // Name the points so they are consistent with the explanation below
        let p4 = other.p2
        let matrix = simd_double2x2(p4 - p3, p1 - p2)
        guard matrix.determinant != 0 else { return nil } // Determinent == 0 => parallel lines
        let multipliers = matrix.inverse * (p1 - p3)
        // If either of the multipliers is outside the range 0 ... 1, then the
        // intersection would be off the end of one of the line segments.
        guard (0.0 ... 1.0).contains(multipliers.x) && (0.0 ... 1.0).contains(multipliers.y)
            else { return nil }
        return p1 + multipliers.y * (p2 - p1)
    }
}

该算法有效,因为如果您有由p3和p4定义的两个点p1和p2以及由b3和p4定义的线段b定义的线段,则a和b上的点分别由

  • p1 + ta(p2 - p1)
  • p3 + tb(p4 - p3)

所以交叉点就在哪里

p1 + ta(p2 - p1)= p3 + tb(p4 - p3)

这可以重新排列为

p1 - p3 = tb(p4 - p3)+ ta(p1 - p2)

有一点jiggery pokery你可以得到以下等价物

p1 - p3 = A.t

其中t是向量(tb,ta),A是矩阵,其列为p4 - p3和p1 - p2

等式可以重新排列为

A-1(p1-p3)= t

左侧的所有东西都已知或可以计算得到我们。 t的任何一个分量都可以插入相应的原始方程中以得到交点(NB浮点舍入误差将意味着两个答案可能不完全相同但非常接近)。

注意,如果线是平行的,则A的行列式将为零。此外,如果任一组件在0 ... 1范围之外,则需要扩展一个或两个线段以到达交叉点。

© www.soinside.com 2019 - 2024. All rights reserved.