I'm working with LibGDX and I have a Line Segment (x1, y1, x2, y2) intersecting a circle with the center (cx, cy) and a radius R.
How can I determine the coordinates of the intersection points using LibGDX (or pure Java)?
I'm checked the Intersector.intersectSegmentCircle
method, but this return only true
or false
without return the intersection points coordinates.
I thanks for any help.
Here's my solution.
Basically a parametric equation of the line is found, then each coordinate is replaced in the equation of the circle, and we solve for t
using the quadratic formula. The values obtained are used to get the points coordinates. See the answer here for a more in-depth explanation of the math. Additionally, since the line is not infinite in this case, a check is made to see if the intersection points obtained fit in the same rectangle that the line fits in.
I used the same symbols that you use in the figure.
public class Intersections {
/**
* Returns a list of intersection points between the edge of a circle and a line.
* @param cx Circle center X coordinate.
* @param cy Circle center Y coordinate.
* @param r Circle radius.
* @param x1 First line X coordinate.
* @param y1 First line Y coordinate.
* @param x2 Second line X coordinate.
* @param y2 Second line Y coordinate.
* @return A list of intersection points.
*/
public static List<Vector2> getCircleLineIntersectionPoints(
float cx, float cy, float r, float x1, float y1, float x2, float y2) {
// Find values to use in quadratic formula
float dx = x2 - x1;
float dy = y2 - y1;
float a = dx * dx + dy * dy;
float b = 2 * dx * (x1 - cx) + 2 * dy * (y1 - cy);
float c = (float) Math.pow((x1 - cx), 2) + (float) Math.pow((y1 - cy), 2) - r * r;
float d = b * b - 4 * a * c; // Discriminant
ArrayList<Vector2> points = new ArrayList<>();
if (d >= 0) {
// Perform quadratic formula to get 2 points
float root = (float) Math.sqrt(d);
float t1 = 2 * c / (-b + root);
float t2 = 2 * c / (-b - root);
// Need the rectangle bounds that the line fits in to check
// if intersection points are within the line bounds
float xmin = Math.min(x1, x2);
float ymin = Math.min(y1, y2);
float xmax = Math.max(x1, x2);
float ymax = Math.max(y1, y2);
// Add first point
float p1x = x1 + dx * t1;
float p1y = y1 + dy * t1;
if (isPointInRectangle(xmin, ymin, xmax, ymax, p1x, p1y)) {
points.add(new Vector2(p1x, p1y));
}
// Add second point if there's one
if (!MathUtils.isEqual(t1, t2)) {
float p2x = x1 + dx * t2;
float p2y = y1 + dy * t2;
if (isPointInRectangle(xmin, ymin, xmax, ymax, p2x, p2y)) {
points.add(new Vector2(p2x, p2y));
}
}
}
return points;
}
private static boolean isPointInRectangle(
float xmin, float ymin, float xmax, float ymax, float px, float py) {
return px >= xmin && py >= ymin && px <= xmax && py <= ymax;
}
}
Note that this fails and returns no points if both line points are the same but on the edge of the circle. I didn't test it much so make sure it works for all your cases.
EDIT: Instead of checking whether points are in the rectangle, it would be possible to check if the t
values are between 0 and 1. However x1
, y1
, x2
, y2
would need to be replaced with xmin
, ymin
, xmax
, ymax
everywhere.