/**
* Copyright (c) 2009-2011, chunquedong(YangJiandong)
*
* This file is part of ChunMap project
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE(Version >=3)
*
* History:
* 2010-05-05 Jed Young Creation
*/
package chunmap.model.elem;
import chunmap.model.coord.CPoint;
import chunmap.model.coord.Coordinate2D;
import chunmap.util.math.MyDouble;
/**
* 直线
*
* @author chunquedong
*
*/
public class Line {
private double k;// 斜率
private double b;// 截距
private boolean isVertical = false;
/**
* 两点式
*/
public Line(CPoint p1, CPoint p2) {
double dy = p2.getY() - p1.getY();
double dx = p2.getX() - p1.getX();
if (p1.equals(p2))
throw new IllegalArgumentException(
"need tow different points to make one line");
// 竖直线时
if (dx == 0) {
k = Double.POSITIVE_INFINITY;
b = p1.getX();// b变为x轴的截距
isVertical = true;
} else {
k = dy / dx;
b = p1.getY() - k * p1.getX();
}
}
/**
* 截距式
*/
public Line(double k, double b) {
if (Double.isInfinite(k))
isVertical = true;
this.k = k;
this.b = b;
}
/**
* 点斜式
*/
public Line(CPoint p, double k) {
if (Double.isInfinite(k)) {
k = Double.POSITIVE_INFINITY;
b = p.getX();
isVertical = true;
} else {
b = p.getY() - k * p.getX();
this.k = k;
}
}
// ------------------------------------------------------------
public boolean isVertical() {
return isVertical;
}
public double getY(double x) {
if (isVertical)
return Double.NaN;// 竖直
return k * x + b;
}
public double getX(double y) {
if (isVertical)
return b;// 竖直
if (k == 0)
return Double.NaN;// 水平
return (y - b) / k;
}
/**
* 斜率
*
* @return
*/
public double getK() {
if (isVertical)
return Double.POSITIVE_INFINITY;
return k;
}
/**
* 截距
*
* @return
*/
public double getB() {
return b;
}
/**
* 垂直线的斜率
*
* @return
*/
public double getVerticalK() {
if (isVertical)
return 0;
else if (k == 0)
return Double.POSITIVE_INFINITY;
return -1d / k;
}
// ------------------------------------------------------------
/**
* 两线交点,平行返回null
*/
public CPoint crossPoint(Line l2) {
double k1 = this.getK();
double b1 = this.getB();
double k2 = l2.getK();
double b2 = l2.getB();
if (this.isVertical() && l2.isVertical()) {
return null;
} else if (this.isVertical()) {
double y = l2.getY(this.b);
return new Coordinate2D(this.b, y);
} else if (l2.isVertical()) {
double y = this.getY(l2.b);
return new Coordinate2D(l2.b, y);
} else if (k1 == k2) {
return null;// 平行
} else if (k1 == 0) {
double x = l2.getX(this.b);
return new Coordinate2D(x, this.b);
} else if (k2 == 0) {
double x = this.getX(l2.b);
return new Coordinate2D(x, l2.b);
}
double x = (b1 - b2) / (k2 - k1);
double y = this.getY(x);
return new Coordinate2D(x, y);
}
/**
* 点到直线的距离
*
* @param point
* @return
*/
public double distance(CPoint point) {
Line vertical = new Line(point, getVerticalK());
CPoint crossP = crossPoint(vertical);
return point.distance2D(crossP);
}
/**
* 点是否在线上,近似值
*
* @param p
* @return
*/
public boolean onLine(CPoint p) {
// 线垂直时
if (isVertical()) {
return p.getX() == getB();
}
double expectedY = getY(p.getX());
return MyDouble.approximateEquals(expectedY, p.getY());
}
}