10

I have a Line Segment (x1, y1, x2, y2) intersecting a circle of radius r. How can I determine which intersection point is closest to (x1, y1)?

circle-line

andand
  • 17,134
  • 11
  • 53
  • 79
Vali Rosca
  • 479
  • 2
  • 4
  • 18
  • 1
    Can you explain what you mean by the "closest intersection point" Is that a point on the circle? A point on the segment? Something not on either? – andand Apr 11 '14 at 15:29
  • 4
    This is a basic math question and translating the solution to C# is really straight forward and does not make the question any more relevant. – Daniel Brückner Apr 11 '14 at 15:30
  • @andand Intersection point belongs to the both lines. – Dmitry Apr 11 '14 at 15:32
  • @Dmitry The OP speaks of a line segment and a circle. What is the nature of this second line to which you refer? – andand Apr 11 '14 at 15:35
  • @andand I added an image – Vali Rosca Apr 11 '14 at 15:37
  • Do you know how to find the intersection points between your line and your circle, and not know how to find which one is closer, or do you not know how to find the two intersecting points? – Servy Apr 11 '14 at 15:42
  • @Vali Thanks. The picture makes it clearer. Try looking through http://mathworld.wolfram.com/Circle-LineIntersection.html. Implement something and if you're having difficulty, post your code and describe how it's not meeting your expectations. As written, though, this question is off topic for this site. – andand Apr 11 '14 at 15:42
  • @andand Sorry, maybe in English a circle isn't a line. Maybe curve / geometric primitive / shape is a better term? Vali, Solve a system of equations and find both intersection points. – Dmitry Apr 11 '14 at 15:42
  • @Dmitry Understood. Yes in English, curve is the more general term. Lines and line segments are straight (defined in the 2D case by ax + by = c) in Euclidean Geometry. – andand Apr 11 '14 at 15:55

1 Answers1

16

To do that first find the intersection points with the circle and then take the closest one to the line start point

So Check this code

//cx,cy is center point of the circle 
public PointF ClosestIntersection(float cx, float cy, float radius,
                                  PointF lineStart, PointF lineEnd)
{
    PointF intersection1;
    PointF intersection2;
    int intersections = FindLineCircleIntersections(cx, cy, radius, lineStart, lineEnd, out intersection1, out intersection2);

    if (intersections == 1)
        return intersection1; // one intersection

    if (intersections == 2)
    {
        double dist1 = Distance(intersection1, lineStart);
        double dist2 = Distance(intersection2, lineStart);

        if (dist1 < dist2)
            return intersection1;
        else
            return intersection2;
    }

    return PointF.Empty; // no intersections at all
}

private double Distance(PointF p1, PointF p2)
{
    return Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
}

// Find the points of intersection.
private int FindLineCircleIntersections(float cx, float cy, float radius,
                                        PointF point1, PointF point2, out               
                                        PointF intersection1, out PointF intersection2)
{
    float dx, dy, A, B, C, det, t;

    dx = point2.X - point1.X;
    dy = point2.Y - point1.Y;

    A = dx * dx + dy * dy;
    B = 2 * (dx * (point1.X - cx) + dy * (point1.Y - cy));
    C = (point1.X - cx) * (point1.X - cx) + (point1.Y - cy) * (point1.Y - cy) - radius * radius;

    det = B * B - 4 * A * C;
    if ((A <= 0.0000001) || (det < 0))
    {
        // No real solutions.
        intersection1 = new PointF(float.NaN, float.NaN);
        intersection2 = new PointF(float.NaN, float.NaN);
        return 0;
    }
    else if (det == 0)
    {
        // One solution.
        t = -B / (2 * A);
        intersection1 = new PointF(point1.X + t * dx, point1.Y + t * dy);
        intersection2 = new PointF(float.NaN, float.NaN);
        return 1;
    }
    else
    {
        // Two solutions.
        t = (float)((-B + Math.Sqrt(det)) / (2 * A));
        intersection1 = new PointF(point1.X + t * dx, point1.Y + t * dy);
        t = (float)((-B - Math.Sqrt(det)) / (2 * A));
        intersection2 = new PointF(point1.X + t * dx, point1.Y + t * dy);
        return 2;
    }
}

Intersection Code form here LINK

Jhonny007
  • 1,698
  • 1
  • 13
  • 33
yazan
  • 600
  • 7
  • 12
  • 4
    The order of distances doesn't change by sqrt, therefore it's better to leave them squared for better speed. – Preza8 Jul 08 '15 at 15:35
  • Also - I'm not sure if Math.Pow is the fastest way... And it might in fact not be fastest to handle the special case of det = 0 specially, since it can cause branch mispredictions. In fact if the special case is rare, as I expect it to be, the branch misprediction will happen in the special case and might overshadow any performance gains... While adding a small amount of CPU cycles to the general case. – Jesper Nov 13 '19 at 14:33