简体   繁体   English

坐标中两条线之间的交点

[英]Intersection between two lines in coordinates

I can detect the intersection point of two lines, but if my line don't has the length of my screen, it detects the point, where it shouldn't be.我可以检测两条线的交点,但是如果我的线没有屏幕的长度,它会检测到它不应该在的点。

Here a preview:这里有一个预览:路口 So, it shouldn't detect this intersection because the horizontal line isn't that long.所以,它不应该检测到这个交叉点,因为水平线没有那么长。

Code:代码:

- (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;
}

If I understand your question correctly, you need to determine the intersection point of two line segments .如果我正确理解你的问题,你需要确定两条线段的交点。 This should work with the following method:这应该使用以下方法:

- (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];
}

This is a slightly modified version of Hayden Holligan's answer to work with Swift 3:这是Hayden Holligan使用 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))
}

Swift version迅捷版

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

That's the correct equation:这是正确的等式:

+(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;  
}  

Here is another solution in Swift 4.2.这是 Swift 4.2 中的另一个解决方案。 This is functionally identical to MartinR's solution but uses simd vectors and matrices to clean it up.这在功能上与 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)
    }
}

The algorithm works because, if you have line segment a defined by two points p 1 and p 2 and line segment b defined by p 3 and p 4 the points on a and b are respectively defined by该算法工作,因为,如果你有线段上的两点P 1P 2及线段b。通过34的点上限定的和b定义分别由下式定义

  • p 1 + t a ( p 2 - p 1 ) p 1 + t a ( p 2 - p 1 )
  • p 3 + t b ( p 4 - p 3 ) p 3 + t b ( p 4 - p 3 )

so the point of intersection would be where所以交点将是

p 1 + t a ( p 2 - p 1 ) = p 3 + t b ( p 4 - p 3 ) p 1 + t a ( p 2 - p 1 ) = p 3 + t b ( p 4 - p 3 )

This can be rearranged as这可以重新排列为

p 1 - p 3 = t b ( p 4 - p 3 ) + t a ( p 1 - p 2 ) p 1 - p 3 = t b ( p 4 - p 3 ) + t a ( p 1 - p 2 )

and with a bit of jiggery pokery you can get to the following equivalent并通过一些jiggery pokery,您可以得到以下等价物

p 1 - p 3 = A . p 1 - p 3 = A。 t

where t is the vector (t b , t a ) and A is the matrix whose columns are p 4 - p 3 and p 1 - p 2其中t是向量 (t b , t a ), A是矩阵,其列是p 4 - p 3p 1 - p 2

The equation can be rearranged as该方程可以重新排列为

A -1 ( p 1 - p 3 ) = t A -1 ( p 1 - p 3 ) = t

Everything on the left hand side is already known or can be calculated to get us t .左侧的所有内容都是已知的,或者可以通过计算得到我们t Either of the components of t can be plugged into the respective original equation to get the intersection point (NB floating point rounding errors will mean that the two answers probably aren't exactly the same but are very close). t 的任何一个分量都可以插入各自的原始方程以获得交点(NB 浮点舍入误差将意味着两个答案可能不完全相同但非常接近)。

Note that, if the lines are parallel, the determinant of A will be zero.请注意,如果线平行,则A的行列式将为零。 Also, if either component is outside the range 0 ... 1 , then one or both line segments needs to be extended to get to the point of intersection.此外,如果任一组件在0 ... 1范围之外,则需要延伸一条或两条线段以到达交点。

I know the answer is given and all of them are correct one still, I feel to give my answer to this question.我知道答案已经给出,而且所有答案都是正确的,我觉得要回答这个问题。 So here it is.所以在这里。

func linesCross(start1: CGPoint, end1: CGPoint, start2: CGPoint, end2: CGPoint) -> (x: CGFloat, y: CGFloat)? {
// calculate the differences between the start and end X/Y positions for each of our points
let delta1x = end1.x - start1.x
let delta1y = end1.y - start1.y
let delta2x = end2.x - start2.x
let delta2y = end2.y - start2.y

// create a 2D matrix from our vectors and calculate the determinant
let determinant = delta1x * delta2y - delta2x * delta1y

if abs(determinant) < 0.0001 {
    // if the determinant is effectively zero then the lines are parallel/colinear
    return nil
}

// if the coefficients both lie between 0 and 1 then we have an intersection
let ab = ((start1.y - start2.y) * delta2x - (start1.x - start2.x) * delta2y) / determinant

if ab > 0 && ab < 1 {
    let cd = ((start1.y - start2.y) * delta1x - (start1.x - start2.x) * delta1y) / determinant

    if cd > 0 && cd < 1 {
        // lines cross – figure out exactly where and return it
        let intersectX = start1.x + ab * delta1x
        let intersectY = start1.y + ab * delta1y
        return (intersectX, intersectY)
    }
}

// lines don't cross
return nil
}

I get this from this site .我从这个网站得到这个。

This one is very simple and easy, too.这个也非常简单和容易。

Happy Coding :)快乐编码:)

This answer is available in several programming languages此答案可用于多种编程语言

https://rosettacode.org/wiki/Find_the_intersection_of_two_lines https://rosettacode.org/wiki/Find_the_intersection_of_two_lines

struct Point {
  var x: Double
  var y: Double
}
 
struct Line {
  var p1: Point
  var p2: Point
 
  var slope: Double {
    guard p1.x - p2.x != 0.0 else { return .nan }
 
    return (p1.y-p2.y) / (p1.x-p2.x)
  }
 
  func intersection(of other: Line) -> Point? {
    let ourSlope = slope
    let theirSlope = other.slope
 
    guard ourSlope != theirSlope else { return nil }
 
    if ourSlope.isNaN && !theirSlope.isNaN {
      return Point(x: p1.x, y: (p1.x - other.p1.x) * theirSlope + other.p1.y)
    } else if theirSlope.isNaN && !ourSlope.isNaN {
      return Point(x: other.p1.x, y: (other.p1.x - p1.x) * ourSlope + p1.y)
    } else {
      let x = (ourSlope*p1.x - theirSlope*other.p1.x + other.p1.y - p1.y) / (ourSlope - theirSlope)
      return Point(x: x, y: theirSlope*(x - other.p1.x) + other.p1.y)
    }
  }
}
 
let l1 = Line(p1: Point(x: 4.0, y: 0.0), p2: Point(x: 6.0, y: 10.0))
let l2 = Line(p1: Point(x: 0.0, y: 3.0), p2: Point(x: 10.0, y: 7.0))
 
print("Intersection at : \(l1.intersection(of: l2)!)")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM