椭圆和线交叉JAVA

时间:2014-06-11 13:41:16

标签: java geometry line intersection ellipse

我有一个椭圆,中点'中',水平半径'h',垂直半径'v'和Line2D。

现在我需要一些代码来计算两者的两个交点。 我已经尝试了一些代码并自己尝试了但是总是有一个错误。

有人有一些工作代码吗?

3 个答案:

答案 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)

当行由P0P1两个点给出时,该行的任何点都为(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检查它们是否属于线段。交叉点本身由第一个等式给出。

相关问题