使用java2D在圆圈中找到点的快速方法

时间:2013-12-30 19:43:40

标签: java performance geometry java-2d

要查找点P(x,y)是否位于具有中心(x1,y1)的圆内,有两种可能的方法:

  1. 在Point2D类中使用distance()函数。这个相当于距离公式法。

    if (new Point(x1, y1).distance(x, y) < Diam/2)

  2. 在Ellipse2D.Double中使用contains()函数。这个检查点是否位于圆圈内。

    if (new Ellipse2D.Double(x1, y1, Diam, Diam).contains(new Point(x, y)));

  3. 这两个函数都内置在java2D中。但出于好奇,我想知道哪一个在性能方面更快/更好。有什么想法吗?

4 个答案:

答案 0 :(得分:3)

来自java来源:

的Point2D:

public static double distance(double x1, double y1,
                              double x2, double y2)
{
    x1 -= x2;
    y1 -= y2;
    return Math.sqrt(x1 * x1 + y1 * y1);
}

Ellipse2D的:

public boolean contains(double x, double y) {
    // Normalize the coordinates compared to the ellipse
    // having a center at 0,0 and a radius of 0.5.
    double ellw = getWidth();
    if (ellw <= 0.0) {
        return false;
    }
    double normx = (x - getX()) / ellw - 0.5;
    double ellh = getHeight();
    if (ellh <= 0.0) {
        return false;
    }
    double normy = (y - getY()) / ellh - 0.5;
    return (normx * normx + normy * normy) < 0.25;
}

所以椭圆几乎没有什么可做,但没有sqrt()。

但你为什么不绕圈子让我们知道呢? ;)

编辑:

因此,让我为您完成这些复杂的信息技术: (我很年轻,需要积分)

    Point2D A = new Point2D.Double( 1.0, 2.0 );
    Point2D B = new Point2D.Double( 2.0, 1.0 );

    Ellipse2D E = new Ellipse2D.Double( 1.0, 2.0, 2.0, 1.0 );

    double x = 1.0;
    double c=0; // Keep compiler from optimizing
    boolean y = false;

    long start = System.currentTimeMillis();
    for( long i=0; i<1000000000L; i++ ){
        y |= E.contains( B );
    }
    long durA = System.currentTimeMillis() - start;

    start = System.currentTimeMillis();
    for( long i=0; i<1000000000L; i++ ){
        c += A.distance( B ) - x/2.0;
    }
    long durB = System.currentTimeMillis() - start;

    System.out.println( y ); // Keep compiler from optimizing
    System.out.println( c );
    System.out.printf( "%d / %d", durA, durB );

将在我的系统中产生:

324 / 946

正如其他人所指出的那样:速度的主要区别在于使用sqrt()来返回距离。 Ellipse2D中的比较不需要返回距离,可以使用更快的方法。

所以第二种方法更快。请注意,这是1,000,000,000次运行。所以实际上这种差异几乎不可察觉。因此,这不是“真正的”基准。有许多效果会导致明显不同的结果。

答案 1 :(得分:2)

最好的方法绝对是你不必采取平方根以应用毕达哥拉斯的方法。这意味着你不测试:

distance <= radius

但相反,你这样做:

distance^2 <= radius^2

这是一种方法:

/**
 * @param x  The x coordinate of the point to test.
 * @param y  The y coordinate of the point to test.
 * @param cX The x coordinate of the center of the circle.
 * @param cY The y coordinate of the center of the circle.
 * @param r  The radius of the circle.
 */
public static boolean liesInCircle(double x, double y, double cX, double cY, double r)
{
   double dx = x - cX;
   double dy = y - cY;
   return dx * dx + dy * dy <= r * r;
} 

答案 2 :(得分:0)

更快的方法实际上是

double dx = x1-x;
double dy = y1-y;
if(dx*dx+dy*dy< Diam*Diam/4)

因为它将避免在第一种方法中执行sqrt(),并且比第二种方法更适合圆形。此外,您可以避免创建不会再次使用的对象。

答案 3 :(得分:0)

查看源代码,看起来Point方法使用标准距离函数:

sqrt((x1 - x2)^2 + (y1 - y2)^2)

Ellipse方法使用毕达哥拉斯定理的一些近似值:

((x - Cx) / (Dx - 0.5))^2 + ((y - Cy) / (Dy - 0.5))^2 < 0.25

正如已经指出的那样,Ellipse方法应该更快,因为它不必使用平方根。