是否应该编写distance()方法

时间:2015-05-24 12:45:49

标签: java oop

关于以下代码,我可以更好地使用distance()方法吗? 感觉它并不完全是这种方法的OOP ..如何才能将代码更改为更好的OOD呢?

谢谢!

public class Line extends Shape {

    private Point lineP1; 
    private Point lineP2;

    public Line(int x1, int x2, int y1, int y2, Color myColor) {
        super(x1, x2, y1, y2, myColor);

        lineP1 = new Point(this.getX1(),this.getY1());
        lineP2 = new Point(this.getX2(),this.getY2());
    }



    @Override
    public void draw(Graphics g) {      
        g.drawLine(this.getX1(), this.getY1(), this.getX2(), this.getY2()); 
        g.setColor(Color.GREEN);
    }

    @Override
    public boolean contains(Point p) {
        if((this.distance(lineP1, p)+this.distance(lineP2, p)) == this.distance(lineP1, lineP2))
            return true;
        return false;
    }

    /**@return distance between two given points
     * This method return the distance between two given points*/
    private double distance(Point p1,Point p2 ){
        return Math.sqrt(Math.pow((p1.getX()-p2.getX()), 2) + Math.pow((p1.getY()-p2.getY()), 2));
    }

}//class Line

1 个答案:

答案 0 :(得分:0)

您的距离方法似乎没问题(但如果您保存变量的差异并使用*运算符将这些值与自己相乘而使用Math.pow),则效果会更好。

然而,由于浮点计算倾向于返回不精确的结果,我不建议使用终点节点和点之间的距离之和来测试作为标准。

但是,如果一个点接近一条线,还有另一个好方法:使用hesse normal form。它的工作原理如下:

P1P2成为与终点相对应的向量。 *表示标量乘法,||表示向量的长度:

D = (P2 - P1) / |P2 - P1|;

N为带有坐标的矢量D,新的x坐标乘以-1(即与D正交的矢量)。

然后可以像这样确定点H到线的距离

| N * H - N * P1 |

如果HP1之间的P2可以像这样检查(假设不失一般性D * P1 < D * P2):

D * P1 <= D * H <= D * P2

使用标量积有额外的好处,计算标量积只需要在2D空间中进行2次乘法和1次加法。

这是你在java代码中执行此操作的方法

// components of normal vector
private double normalX;
private double normalY;

// components of direction vector
private double directionX;
private double directionY;

// the value of (N * P) for all points P on the line
private double normalScalarProduct;

// the range allowed for (D * P) for points on the line
private double minDirectionScalarProduct;
private double maxDirectionScalarProduct;

// error ranges; adjust as appropriate
private static final double directionAllowedError = 0.1;
private static final double normalAllowedError = 0.1;

public Line(int x1, int x2, int y1, int y2, Color myColor) {
    ...
    double dx = x2 - x1;
    double dy = y2 - y1;
    double length = distance(dx, dy);
    if (length == 0) {
        // choose arbitrary direction, if length == 0
        length = 1;
        dx = 1;
    }

    // normalize direction
    dx /= length;
    dy /= length;

    // set D and N values
    this.directionX = dx;
    this.directionY = dy;
    this.normalX = -dy;
    this.normalY = dx;

    double prod1 = scalarProduct(directionX, directionY, x1, y1);
    double prod2 = scalarProduct(directionX, directionY, x2, y2);

    if (prod1 < prod2) {
        minDirectionScalarProduct = prod1 - directionAllowedError;
        maxDirectionScalarProduct = prod2 + directionAllowedError;
    } else {
        minDirectionScalarProduct = prod2 - directionAllowedError;
        maxDirectionScalarProduct = prod1 + directionAllowedError;
    }

    normalScalarProduct = scalarProduct(x1, y1, normalX, normalY);
}

private static double scalarProduct(double x1, double y1, double x2, double y2) {
    return x1*x2 + y1*y2;
}

public boolean contains(Point p) {
    if (Math.abs(scalarProduct(p.getX(), p.getX(), normalX, normalY) - normalScalarProduct) <= normalAllowedError) {
        // close enough to the line -> check, if between end points
        double d = scalarProduct(p.getX(), p.getX(), directionX, directionY);
        return minDirectionScalarProduct <= d && d <= maxDirectionScalarProduct;
    }
    return false;
}

private double distance(double dx, double dy) {
    return Math.sqrt(dx*dx + dy*dy);
}