public static ArrayList<IntPoint> getCircleLineIntersectionPoint(IntPoint pointA, IntPoint pointB, IntPoint center, int radius) {
// returns a list of intersection points between a line which passes through given points,
// pointA and pointB, and a circle described by given radius and center coordinate
double disc, A, B, C, slope, c;
double x1, x2, y1, y2;
IntPoint point1, point2;
ArrayList<IntPoint> intersections = new ArrayList<IntPoint>();
try{
slope = Util.calculateSlope(pointA, pointB);
}catch (UndefinedSlopeException e){
C = Math.pow(center.y, 2) + Math.pow(pointB.x, 2) - 2 * pointB.x * center.x + Math.pow(center.x, 2) - Math.pow(radius, 2);
B = -2 * center.y;
A = 1;
disc = Math.pow(B, 2) - 4 * 1 * C;
if (disc < 0){
return intersections;
}
else{
y1 = (-B + Math.sqrt(disc)) / (2 * A);
y2 = (-B - Math.sqrt(disc)) / (2 * A);
x1 = pointB.x;
x2 = pointB.x;
}
point1 = new IntPoint((int)x1, (int)y1);
point2 = new IntPoint((int)x2, (int)y2);
if (Util.euclideanDistance(pointA, point2) > Util.euclideanDistance(pointA, point1)){
intersections.add(point1);
}
else{
intersections.add(point2);
}
return intersections;
}
if (slope == 0){
C = Math.pow(center.x, 2) + Math.pow(center.y, 2) + Math.pow(pointB.y, 2) - 2 * pointB.y * center.y - Math.pow(radius, 2);
B = -2 * center.x;
A = 1;
disc = Math.pow(B, 2) - 4 * 1 * C;
if (disc < 0){
return intersections;
}
else{
x1 = (-B + Math.sqrt(disc)) / (2*A);
x2 = (-B - Math.sqrt(disc)) / (2*A);
y1 = pointB.y;
y2 = pointB.y;
}
}
else{
c = slope * pointA.x + pointA.y;
B = (2 * center.x + 2 * center.y * slope + 2 * c * slope);
A = 1 + Math.pow(slope, 2);
C = (Math.pow(center.x, 2) + Math.pow(c, 2) + 2 * center.y * c + Math.pow(center.y, 2) - Math.pow(radius, 2));
disc = Math.pow(B, 2) - (4 * A * C);
if (disc < 0){
return intersections;
}
else{
x1 = (-B + Math.sqrt(disc)) / (2 * A);
x2 = (-B - Math.sqrt(disc)) / (2 * A);
y1 = slope * x1 - c;
y2 = slope * x2 - c;
}
}
point1 = new IntPoint((int)x1, (int)y1);
point2 = new IntPoint((int)x2, (int)y2);
if (Util.euclideanDistance(pointA, point2) > Util.euclideanDistance(pointA, point1)){
//if (Util.angleBetween(pointA, pointB, point1) < Math.PI/2){
intersections.add(point1);
//}
}
else{
//if (Util.angleBetween(pointA, pointB, point1) < Math.PI/2){
intersections.add(point2);
//}
}
return intersections;
}
我正在使用上述算法来测试圆和直线之间的交点。有时它工作正常,但有时却失败。该代码表示从圆和直线方程
(x-a)^+(y-b)^2=r^2
和y = mx - mx1 + y1
同时求解x得出的方程。有谁知道我在数学上或其他地方哪里出错了? 最佳答案
您的计算似乎很长,我看不到您测试的不同案例的使用。
无论如何,由于我发现了有趣的问题,所以我尝试自己解决该问题,并提出了以下解决方案。可以用double radius
替换int radius
并使用IntPoint
,但是请注意,如注释中所述,每次转换时,结果都不是精确的整数交点将成为错误。
进行计算的背景是这样的:从点A开始, vector AB的缩放版本指向圆上的点。该点具有距中心的距离半径。因此,| AC + scaleFactor * AB | = r。
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CircleLine {
public static List<Point> getCircleLineIntersectionPoint(Point pointA,
Point pointB, Point center, double radius) {
double baX = pointB.x - pointA.x;
double baY = pointB.y - pointA.y;
double caX = center.x - pointA.x;
double caY = center.y - pointA.y;
double a = baX * baX + baY * baY;
double bBy2 = baX * caX + baY * caY;
double c = caX * caX + caY * caY - radius * radius;
double pBy2 = bBy2 / a;
double q = c / a;
double disc = pBy2 * pBy2 - q;
if (disc < 0) {
return Collections.emptyList();
}
// if disc == 0 ... dealt with later
double tmpSqrt = Math.sqrt(disc);
double abScalingFactor1 = -pBy2 + tmpSqrt;
double abScalingFactor2 = -pBy2 - tmpSqrt;
Point p1 = new Point(pointA.x - baX * abScalingFactor1, pointA.y
- baY * abScalingFactor1);
if (disc == 0) { // abScalingFactor1 == abScalingFactor2
return Collections.singletonList(p1);
}
Point p2 = new Point(pointA.x - baX * abScalingFactor2, pointA.y
- baY * abScalingFactor2);
return Arrays.asList(p1, p2);
}
static class Point {
double x, y;
public Point(double x, double y) { this.x = x; this.y = y; }
@Override
public String toString() {
return "Point [x=" + x + ", y=" + y + "]";
}
}
public static void main(String[] args) {
System.out.println(getCircleLineIntersectionPoint(new Point(-3, -3),
new Point(-3, 3), new Point(0, 0), 5));
System.out.println(getCircleLineIntersectionPoint(new Point(0, -2),
new Point(1, -2), new Point(1, 1), 5));
System.out.println(getCircleLineIntersectionPoint(new Point(1, -1),
new Point(-1, 0), new Point(-1, 1), 5));
System.out.println(getCircleLineIntersectionPoint(new Point(-3, -3),
new Point(-2, -2), new Point(0, 0), Math.sqrt(2)));
}