关于以下代码,我可以更好地使用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
答案 0 :(得分:0)
您的距离方法似乎没问题(但如果您保存变量的差异并使用*
运算符将这些值与自己相乘而使用Math.pow
),则效果会更好。
然而,由于浮点计算倾向于返回不精确的结果,我不建议使用终点节点和点之间的距离之和来测试作为标准。
但是,如果一个点接近一条线,还有另一个好方法:使用hesse normal form。它的工作原理如下:
让P1
和P2
成为与终点相对应的向量。 *
表示标量乘法,||
表示向量的长度:
D = (P2 - P1) / |P2 - P1|;
让N
为带有坐标的矢量D
,新的x坐标乘以-1
(即与D正交的矢量)。
然后可以像这样确定点H
到线的距离
| N * H - N * P1 |
如果H
和P1
之间的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);
}