Task: Line circle intersection




Go: package main

import (
    "fmt"
    "math"
)

const eps = 1e-14 

type point struct{ x, y float64 }

func (p point) String() string {
    
    
    if p.x == 0 {
        p.x = 0
    }
    if p.y == 0 {
        p.y = 0
    }
    return fmt.Sprintf("(%g, %g)", p.x, p.y)
}

func sq(x float64) float64 { return x * x }




func intersects(p1, p2, cp point, r float64, segment bool) []point {
    var res []point
    x0, y0 := cp.x, cp.y
    x1, y1 := p1.x, p1.y
    x2, y2 := p2.x, p2.y
    A := y2 - y1
    B := x1 - x2
    C := x2*y1 - x1*y2
    a := sq(A) + sq(B)
    var b, c float64
    var bnz = true
    if math.Abs(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 {
        
        return res
    }

    
    within := func(x, y float64) bool {
        d1 := math.Sqrt(sq(x2-x1) + sq(y2-y1)) 
        d2 := math.Sqrt(sq(x-x1) + sq(y-y1))   
        d3 := math.Sqrt(sq(x2-x) + sq(y2-y))   
        delta := d1 - d2 - d3
        return math.Abs(delta) < eps 
    }

    var x, y float64
    fx := func() float64 { return -(A*x + C) / B }
    fy := func() float64 { return -(B*y + C) / A }
    rxy := func() {
        if !segment || within(x, y) {
            res = append(res, point{x, y})
        }
    }

    if d == 0 {
        
        if bnz {
            x = -b / (2 * a)
            y = fx()
            rxy()
        } else {
            y = -b / (2 * a)
            x = fy()
            rxy()
        }
    } else {
        
        d = math.Sqrt(d)
        if bnz {
            x = (-b + d) / (2 * a)
            y = fx()
            rxy()
            x = (-b - d) / (2 * a)
            y = fx()
            rxy()
        } else {
            y = (-b + d) / (2 * a)
            x = fy()
            rxy()
            y = (-b - d) / (2 * a)
            x = fy()
            rxy()
        }
    }
    return res
}

func main() {
    cp := point{3, -5}
    r := 3.0
    fmt.Println("The intersection points (if any) between:")
    fmt.Println("\n  A circle, center (3, -5) with radius 3, and:")
    fmt.Println("\n    a line containing the points (-10, 11) and (10, -9) is/are:")
    fmt.Println("     ", intersects(point{-10, 11}, point{10, -9}, cp, r, false))
    fmt.Println("\n    a segment starting at (-10, 11) and ending at (-11, 12) is/are")
    fmt.Println("     ", intersects(point{-10, 11}, point{-11, 12}, cp, r, true))
    fmt.Println("\n    a horizontal line containing the points (3, -2) and (7, -2) is/are:")
    fmt.Println("     ", intersects(point{3, -2}, point{7, -2}, cp, r, false))
    cp = point{0, 0}
    r = 4.0
    fmt.Println("\n  A circle, center (0, 0) with radius 4, and:")
    fmt.Println("\n    a vertical line containing the points (0, -3) and (0, 6) is/are:")
    fmt.Println("     ", intersects(point{0, -3}, point{0, 6}, cp, r, false))
    fmt.Println("\n    a vertical segment starting at (0, -3) and ending at (0, 6) is/are:")
    fmt.Println("     ", intersects(point{0, -3}, point{0, 6}, cp, r, true))
    cp = point{4, 2}
    r = 5.0
    fmt.Println("\n  A circle, center (4, 2) with radius 5, and:")
    fmt.Println("\n    a line containing the points (6, 3) and (10, 7) is/are:")
    fmt.Println("     ", intersects(point{6, 3}, point{10, 7}, cp, r, false))
    fmt.Println("\n    a segment starting at (7, 4) and ending at (11, 8) is/are:")
    fmt.Println("     ", intersects(point{7, 4}, point{11, 8}, cp, r, true))
    cp = point{10, 10}
    r = 5.0
    fmt.Println("\n  A circle, center (10, 10) with radius 5, and:")
    fmt.Println("\n    a vertical line containing the points (5, 0) and (5, 20) is/are:")
    fmt.Println("     ", intersects(point{5, 0}, point{5, 20}, cp, r, false))
    fmt.Println("\n    a horizontal segment starting at (-5, 10) and ending at (5, 10) is/are:")
    fmt.Println("     ", intersects(point{-5, 10}, point{5, 10}, cp, r, true))
}


Java: import java.util.*;
import java.awt.geom.*;

public class LineCircleIntersection {
    public static void main(String[] args) {
        try {
            demo();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void demo() throws NoninvertibleTransformException {
        Point2D center = makePoint(3, -5);
        double radius = 3.0;
        System.out.println("The intersection points (if any) between:");
        System.out.println("\n  A circle, center (3, -5) with radius 3, and:");
        System.out.println("\n    a line containing the points (-10, 11) and (10, -9) is/are:");
        System.out.println("     " + toString(intersection(makePoint(-10, 11), makePoint(10, -9),
                            center, radius, false)));
        System.out.println("\n    a segment starting at (-10, 11) and ending at (-11, 12) is/are");
        System.out.println("     " + toString(intersection(makePoint(-10, 11), makePoint(-11, 12),
                            center, radius, true)));
        System.out.println("\n    a horizontal line containing the points (3, -2) and (7, -2) is/are:");
        System.out.println("     " + toString(intersection(makePoint(3, -2), makePoint(7, -2), center, radius, false)));
        center.setLocation(0, 0);
        radius = 4.0;
        System.out.println("\n  A circle, center (0, 0) with radius 4, and:");
        System.out.println("\n    a vertical line containing the points (0, -3) and (0, 6) is/are:");
        System.out.println("     " + toString(intersection(makePoint(0, -3), makePoint(0, 6),
                            center, radius, false)));
        System.out.println("\n    a vertical segment starting at (0, -3) and ending at (0, 6) is/are:");
        System.out.println("     " + toString(intersection(makePoint(0, -3), makePoint(0, 6),
                            center, radius, true)));
        center.setLocation(4, 2);
        radius = 5.0;
        System.out.println("\n  A circle, center (4, 2) with radius 5, and:");
        System.out.println("\n    a line containing the points (6, 3) and (10, 7) is/are:");
        System.out.println("     " + toString(intersection(makePoint(6, 3), makePoint(10, 7),
                            center, radius, false)));
        System.out.println("\n    a segment starting at (7, 4) and ending at (11, 8) is/are:");
        System.out.println("     " + toString(intersection(makePoint(7, 4), makePoint(11, 8),
                            center, radius, true)));
    }

    private static Point2D makePoint(double x, double y) {
        return new Point2D.Double(x, y);
    }

    
    
    
    
    
    
    
    
    public static List<Point2D> intersection(Point2D p1, Point2D p2, Point2D center,
            double radius, boolean isSegment) throws NoninvertibleTransformException {
        List<Point2D> result = new ArrayList<>();
        double dx = p2.getX() - p1.getX();
        double dy = p2.getY() - p1.getY();
        AffineTransform trans = AffineTransform.getRotateInstance(dx, dy);
        trans.invert();
        trans.translate(-center.getX(), -center.getY());
        Point2D p1a = trans.transform(p1, null);
        Point2D p2a = trans.transform(p2, null);
        double y = p1a.getY();
        double minX = Math.min(p1a.getX(), p2a.getX());
        double maxX = Math.max(p1a.getX(), p2a.getX());
        if (y == radius || y == -radius) {
            if (!isSegment || (0 <= maxX && 0 >= minX)) {
                p1a.setLocation(0, y);
                trans.inverseTransform(p1a, p1a);
                result.add(p1a);
            }
        } else if (y < radius && y > -radius) {
            double x = Math.sqrt(radius * radius - y * y);
            if (!isSegment || (-x <= maxX && -x >= minX)) {
                p1a.setLocation(-x, y);
                trans.inverseTransform(p1a, p1a);
                result.add(p1a);
            }
            if (!isSegment || (x <= maxX && x >= minX)) {
                p2a.setLocation(x, y);
                trans.inverseTransform(p2a, p2a);
                result.add(p2a);
            }
        }
        return result;
    }

    public static String toString(Point2D point) {
        return String.format("(%g, %g)", point.getX(), point.getY());
    }

    public static String toString(List<Point2D> points) {
        StringBuilder str = new StringBuilder("[");
        for (int i = 0, n = points.size(); i < n; ++i) {
            if (i > 0)
                str.append(", ");
            str.append(toString(points.get(i)));
        }
        str.append("]");
        return str.toString();
    }
}