Task: Line circle intersection

C: #include <math.h>
#include <stdbool.h>
#include <stdio.h>

const double eps = 1e-14;

typedef struct point_t {
    double x, y;
} point;

point make_point(double x, double y) {
    point p = { x, y };
    return p;
}

void print_point(point p) {
    double x = p.x;
    double y = p.y;
    if (x == 0) {
        x = 0;
    }
    if (y == 0) {
        y = 0;
    }
    printf("(%g, %g)", x, y);
}

double sq(double x) {
    return x * x;
}

bool within(double x1, double y1, double x2, double y2, double x, double y) {
    double d1 = sqrt(sq(x2 - x1) + sq(y2 - y1));    
    double d2 = sqrt(sq(x - x1) + sq(y - y1));      
    double d3 = sqrt(sq(x2 - x) + sq(y2 - y));      
    double delta = d1 - d2 - d3;
    return fabs(delta) < eps;   
}

int rxy(double x1, double y1, double x2, double y2, double x, double y, bool segment) {
    if (!segment || within(x1, y1, x2, y2, x, y)) {
        print_point(make_point(x, y));
        return 1;
    } else {
        return 0;
    }
}

double fx(double A, double B, double C, double x) {
    return -(A * x + C) / B;
}

double fy(double A, double B, double C, double y) {
    return -(B * y + C) / A;
}




void intersects(point p1, point p2, point cp, double r, bool segment) {
    double x0 = cp.x, y0 = cp.y;
    double x1 = p1.x, y1 = p1.y;
    double x2 = p2.x, y2 = p2.y;
    double A = y2 - y1;
    double B = x1 - x2;
    double C = x2 * y1 - x1 * y2;
    double a = sq(A) + sq(B);
    double b, c, d;
    bool bnz = true;
    int cnt = 0;

    if (fabs(B) >= eps) {
        
        b = 2 * (A * C + A * B * y0 - sq(B) * x0);
        c = sq(C) + 2 * B * C * y0 - sq(B) * (sq(r) - sq(x0) - sq(y0));
    } else {
        b = 2 * (B * C + A * B * x0 - sq(A) * y0);
        c = sq(C) + 2 * A * C * x0 - sq(A) * (sq(r) - sq(x0) - sq(y0));
        bnz = false;
    }
    d = sq(b) - 4 * a * c; 
    if (d < 0) {
        
        printf("[]\n");
        return;
    }

    if (d == 0) {
        
        if (bnz) {
            double x = -b / (2 * a);
            double y = fx(A, B, C, x);
            cnt = rxy(x1, y1, x2, y2, x, y, segment);
        } else {
            double y = -b / (2 * a);
            double x = fy(A, B, C, y);
            cnt = rxy(x1, y1, x2, y2, x, y, segment);
        }
    } else {
        
        d = sqrt(d);
        if (bnz) {
            double x = (-b + d) / (2 * a);
            double y = fx(A, B, C, x);
            cnt = rxy(x1, y1, x2, y2, x, y, segment);

            x = (-b - d) / (2 * a);
            y = fx(A, B, C, x);
            cnt += rxy(x1, y1, x2, y2, x, y, segment);
        } else {
            double y = (-b + d) / (2 * a);
            double x = fy(A, B, C, y);
            cnt = rxy(x1, y1, x2, y2, x, y, segment);

            y = (-b - d) / (2 * a);
            x = fy(A, B, C, y);
            cnt += rxy(x1, y1, x2, y2, x, y, segment);
        }
    }

    if (cnt <= 0) {
        printf("[]");
    }
}

int main() {
    point cp = make_point(3, -5);
    double r = 3.0;
    printf("The intersection points (if any) between:\n");
    printf("  A circle, center (3, -5) with radius 3, and:\n");
    printf("    a line containing the points (-10, 11) and (10, -9) is/are:\n");
    printf("      ");
    intersects(make_point(-10, 11), make_point(10, -9), cp, r, false);
    printf("\n    a segment starting at (-10, 11) and ending at (-11, 12) is/are\n");
    printf("      ");
    intersects(make_point(-10, 11), make_point(-11, 12), cp, r, true);
    printf("\n    a horizontal line containing the points (3, -2) and (7, -2) is/are:\n");
    printf("      ");
    intersects(make_point(3, -2), make_point(7, -2), cp, r, false);
    printf("\n");

    cp = make_point(0, 0);
    r = 4.0;
    printf("  A circle, center (0, 0) with radius 4, and:\n");
    printf("    a vertical line containing the points (0, -3) and (0, 6) is/are:\n");
    printf("      ");
    intersects(make_point(0, -3), make_point(0, 6), cp, r, false);
    printf("\n    a vertical segment starting at (0, -3) and ending at (0, 6) is/are:\n");
    printf("      ");
    intersects(make_point(0, -3), make_point(0, 6), cp, r, true);
    printf("\n");

    cp = make_point(4,2);
    r = 5.0;
    printf("  A circle, center (4, 2) with radius 5, and:\n");
    printf("    a line containing the points (6, 3) and (10, 7) is/are:\n");
    printf("      ");
    intersects(make_point(6, 3), make_point(10, 7), cp, r, false);
    printf("\n    a segment starting at (7, 4) and ending at (11, 8) is/are:\n");
    printf("      ");
    intersects(make_point(7, 4), make_point(11, 8), cp, r, true);
    printf("\n");

    return 0;
}








VB: Module Module1

    Structure Point
        Implements IComparable(Of Point)

        Public Sub New(mx As Double, my As Double)
            X = mx
            Y = my
        End Sub

        Public ReadOnly Property X As Double
        Public ReadOnly Property Y As Double

        Public Function CompareTo(other As Point) As Integer Implements IComparable(Of Point).CompareTo
            Dim c = X.CompareTo(other.X)
            If c <> 0 Then
                Return c
            End If
            Return Y.CompareTo(other.Y)
        End Function

        Public Overrides Function ToString() As String
            Return String.Format("({0}, {1})", X, Y)
        End Function
    End Structure

    Structure Line
        Public Sub New(mp1 As Point, mp2 As Point, Optional segment As Boolean = False)
            If P2.CompareTo(P1) < 0 Then
                P1 = mp2
                P2 = mp1
            Else
                P1 = mp1
                P2 = mp2
            End If
            IsSegment = segment
            If P1.X = P2.X Then
                Slope = Double.PositiveInfinity
                YIntercept = Double.NaN
            Else
                Slope = (P2.Y - P1.Y) / (P2.X - P1.X)
                YIntercept = P2.Y - Slope * P2.X
            End If
        End Sub

        Public ReadOnly Property P1 As Point
        Public ReadOnly Property P2 As Point
        Public ReadOnly Property Slope As Double
        Public ReadOnly Property YIntercept As Double
        Public ReadOnly Property IsSegment As Boolean

        Public Function IsVertical() As Boolean
            Return P1.X = P2.X
        End Function

        Public Overrides Function ToString() As String
            Return String.Format("[{0}, {1}]", P1, P2)
        End Function
    End Structure

    Structure Circle
        Public Sub New(c As Point, r As Double)
            Center = c
            Radius = r
        End Sub

        Public ReadOnly Property Center As Point
        Public ReadOnly Property Radius As Double

        Public Function X() As Double
            Return Center.X
        End Function

        Public Function Y() As Double
            Return Center.Y
        End Function

        Public Overrides Function ToString() As String
            Return String.Format("{{ C:{0}, R:{1} }}", Center, Radius)
        End Function
    End Structure

    Function Intersection(oc As Circle, ol As Line) As IEnumerable(Of Point)
        Dim LineIntersection = Iterator Function(ic As Circle, il As Line) As IEnumerable(Of Point)
                                   Dim m = il.Slope
                                   Dim c = il.YIntercept
                                   Dim p = ic.X
                                   Dim q = ic.Y
                                   Dim r = ic.Radius

                                   If il.IsVertical Then
                                       Dim x = il.P1.X
                                       Dim B = -2 * q
                                       Dim CC = p * p + q * q - r * r + x * x - 2 * p * x
                                       Dim D = B * B - 4 * CC
                                       If D = 0 Then
                                           Yield New Point(x, -q)
                                       ElseIf D > 0 Then
                                           D = Math.Sqrt(D)
                                           Yield New Point(x, (-B - D) / 2)
                                           Yield New Point(x, (-B + D) / 2)
                                       End If
                                   Else
                                       Dim A = m * m + 1
                                       Dim B = 2 * (m * c - m * q - p)
                                       Dim CC = p * p + q * q - r * r + c * c - 2 * c * q
                                       Dim D = B * B - 4 * A * CC
                                       If D = 0 Then
                                           Dim x = -B / (2 * A)
                                           Dim y = m * x + c
                                           Yield New Point(x, y)
                                       ElseIf D > 0 Then
                                           D = Math.Sqrt(D)
                                           Dim x = (-B - D) / (2 * A)
                                           Dim y = m * x + c
                                           Yield New Point(x, y)
                                           x = (-B + D) / (2 * A)
                                           y = m * x + c
                                           Yield New Point(x, y)
                                       End If
                                   End If
                               End Function

        Dim int = LineIntersection(oc, ol)
        If ol.IsSegment Then
            Return int.Where(Function(p) p.CompareTo(ol.P1) >= 0 AndAlso p.CompareTo(ol.P2) <= 0)
        Else
            Return int
        End If
    End Function

    Sub Print(c As Circle, lines() As Line)
        Console.WriteLine("Circle: {0}", c)
        For Each line In lines
            Console.Write(vbTab)
            If line.IsSegment Then
                Console.Write("Segment: ")
            Else
                Console.Write("Line: ")
            End If
            Console.WriteLine(line)

            Dim points = Intersection(c, line).ToList

            Console.Write(vbTab + vbTab)
            If points.Count = 0 Then
                Console.WriteLine("do not intersect")
            Else
                Console.WriteLine("intersect at {0}", String.Join(" and ", points))
            End If
        Next
        Console.WriteLine()
    End Sub

    Sub Main()
        Dim c = New Circle(New Point(3, -5), 3)
        Dim lines() As Line = {
            New Line(New Point(-10, 11), New Point(10, -9)),
            New Line(New Point(-10, 11), New Point(-11, 12), True),
            New Line(New Point(3, -2), New Point(7, -2))
            }
        Print(c, lines)

        c = New Circle(New Point(0, 0), 4)
        lines = {
            New Line(New Point(0, -3), New Point(0, 6)),
            New Line(New Point(0, -3), New Point(0, 6), True)
            }
        Print(c, lines)

        c = New Circle(New Point(4, 2), 5)
        lines = {
            New Line(New Point(6, 3), New Point(10, 7)),
            New Line(New Point(7, 4), New Point(11, 8), True)
            }
        Print(c, lines)
    End Sub

End Module