我有一个椭圆,中点'中',水平半径'h',垂直半径'v'和Line2D。
现在我需要一些代码来计算两者的两个交点。 我已经尝试了一些代码并自己尝试了但是总是有一个错误。
有人有一些工作代码吗?
答案 0 :(得分:2)
你将需要使用代数来解决这两个方程,它会变得有点混乱。首先,你必须写出椭圆
(1) (x/h)^2 + (y/v)^2 = 1
和格式为
的行(2) y = ax + b
首先,移动坐标轴,使椭圆以原点为中心。你可以通过从行中减去mid来做到这一点。计算出交叉点后,通过添加mid来将它们移回。
您可以从线的起点和终点计算delta-y / delta-x的线性斜率。您必须检查斜率是否垂直。如果斜率是垂直的,您只需检查线点的x值是否落在椭圆的位置,然后轻松计算值。在纸上画出来,看看如何计算它。
现在假设斜率不是垂直的。既然你从线上知道了y,那就把它换成(1)。简化给出了二次方程。
(3) ((ah)^2+v^2)x^2 + (2abh^2)x + ((hb)^2-(hv)^2) = 0
使用二次公式给出交点的x坐标的两个值。如果x有两个实数值,则有两个交点。如果x只有一个真正的解,那么就有一个交集。如果x没有真正的解决方案,则没有交集。
鉴于ax ^ 2 + bx + c = 0,x由
给出x = (1/2a)(-b +- Sqrt(b^2 - 4ac))
设D = b ^ 2 - 4ac
如果D< 0,没有交叉点
如果D = 0,则有一个交叉点
如果D> 0,有两个交叉点
计算出x交点的值后,将x的值替换为(2)得到y值。
现在,您需要确保这些点落在行内。为此,只需检查计算点的x和y分量是否满足x1< = x< = x2和y1< = y< = y2,其中x1是最小的,x2是x的最大x-端点线,y1是最小的,y2是线的最大y端点。
以下是我制作的示例方法
public static ArrayList<Point2D> getIntersection(double x1, double x2, double y1, double y2, double midX, double midY, double h, double v) {
ArrayList<Point2D> points = new ArrayList();
x1 -= midX;
y1 -= midY;
x2 -= midX;
y2 -= midY;
if (x1 == x2) {
double y = (v/h)*Math.sqrt(h*h-x1*x1);
if (Math.min(y1, y2) <= y && y <= Math.max(y1, y2)) {
points.add(new Point2D(x1+midX, y+midY);
}
if (Math.min(y1, y2) <= -y && -y <= Math.max(y1, y2)) {
points.add(newPoint2D(x1+midX, -y+midY);
}
}
else {
double a = (y2 - y1) / (x2 - x1);
double b = (y1 - a*x1);
double r = a*a*h*h + v*v;
double s = 2*a*b*h*h;
double t = h*h*b*b - h*h*v*v;
double d = s*s - 4*r*t;
if (d > 0) {
double xi1 = (-s+Math.sqrt(d))/(2*r);
double xi2 = (-s-Math.sqrt(d))/(2*r);
double yi1 = a*xi1+b;
double yi2 = a*xi2+b;
if (isPointInLine(x1, x2, y1, y2, xi1, yi1)) {
points.add(new Point2D.Double(xi1+midX, yi1+midY);
}
if (isPointInLine(x1, x2, y1, y2, xi2, yi2)) {
points.add(new Point2D.Double(xi2+midX, yi2+midY);
}
}
else if (d == 0) {
double xi = -s/(2*r);
double yi = a*xi+b;
if (isPointInLine(x1, x2, y1, y2, xi, yi)) {
points.add(new Point2D.Double(xi+midX, yi+midY));
}
}
}
return points;
}
public static boolean isPointInLine(double x1, double x2, double y1, double y2, double px, double py) {
double xMin = Math.min(x1, x2);
double xMax = Math.max(x1, x2);
double yMin = Math.min(y1, y2);
double yMax = Math.max(y1, y2);
return (xMin <= px && px <= xMax) && (yMin <= py && py <= yMax);
}
随意检查我的代数和代码,但是你应该仔细检查每个代数步骤来解决这个问题。
答案 1 :(得分:1)
我会使用内置的椭圆和线/多边形类,它们都有确定碰撞和交叉的方法
答案 2 :(得分:0)
当行由P0
和P1
两个点给出时,该行的任何点都为(X, Y) = (X0, Y0) + t (X1 - X0, Y1 - Y0) = (X0, Y0) + t (DX, DY)
。
椭圆为(X - Xm)²/h² + (Y - Ym)²/v² = 1
。
我们将使用技巧来简化计算:取所有X
,减去Xm
并除以h
,得到x
;取所有Y
,减去Ym
并除以h
,得到y
。这会将椭圆变成以原点为中心的圆。 (如果您愿意,可以在不减少坐标的情况下进行所有计算。)
现在,(x, y) = (x0, y0) + t (dx, dy)
和x² + y² = 1
。
或(t dx + x0)² + (t dy + y0)² = 1
。
或(dx² + dy²) t² + 2 (dx x0 + dy y0) t + (x0² + y0² - 1) = 0
。
解决t
的第二度方程。如果存在真正的根,则可以通过条件0 <= t <= 1
检查它们是否属于线段。交叉点本身由第一个等式给出。