package com.interview.basics.model.geometry;
import com.interview.utils.FloatAssertion;
import com.interview.utils.GeoUtil;
/**
* Created_By: stefanie
* Date: 15-1-4
* Time: 下午8:58
*/
public class Line {
boolean isSegment;
float A;
float B;
float C;
float[] X;
float[] Y;
public Line(float A, float B, float C){
isSegment = false;
this.A = A;
this.B = B;
this.C = C;
//use x = 0 and 100 as endpoint for line.
sampleEndpoint();
}
private void sampleEndpoint(){
X = new float[2];
X[0] = 0;
X[1] = (C - A * X[0])/B;
Y = new float[2];
Y[0] = 100;
Y[1] = (C - A * Y[0])/B;
}
/**
* A = y2-y1, B = x1-x2, C = A*x1+B*y1
*/
public Line(float[] p1, float[] p2){
isSegment = true;
this.A = p2[1] - p1[1];
this.B = p1[0] - p2[0];
this.C = A * p1[0] + B * p1[1];
X = p1;
Y = p2;
}
public Line(float A, float B, float[] point){
isSegment = false;
this.A = A;
this.B = B;
this.C = A * point[0] + B * point[1];
sampleEndpoint();
}
public float[][] endpoints(){
if(isSegment){
return new float[][]{X, Y};
} else {
return new float[2][0];
}
}
public float distance(float[] Z){
if(isSegment){
if(GeoUtil.dotProduct(X, Y, Z) > 0) return GeoUtil.distance(Y, Z);
if(GeoUtil.dotProduct(Y, X, Z) > 0) return GeoUtil.distance(X, Z);
}
return Math.abs(GeoUtil.crossProduct(X, Y, Z) / GeoUtil.distance(X, Y));
}
/**
* be careful about double precision issues, FloatAssertion.
* @param point
* @return
*/
public boolean onLine(float[] point){
if(isSegment){
if(!FloatAssertion.inRange(point[0], Math.min(X[0], Y[0]), Math.max(X[0], Y[0]))
|| !FloatAssertion.inRange(point[0], Math.min(X[0], Y[0]), Math.max(X[0], Y[0]))) return false;
}
return FloatAssertion.isZero(Math.abs(A * point[0] + B * point[1] - C));
}
public float[] intersection(Line line){
float det = this.A * line.B - line.A * this.B;
if(FloatAssertion.isZero(det)){
return null;
} else {
float x = (line.B * this.C - this.B * line.C)/det;
float y = (this.A * line.C - line.A * this.C)/det;
float[] intersection = new float[]{x, y};
if(isSegment){
if( !this.onLine(intersection) || !line.onLine(intersection)) return null;
}
return intersection;
}
}
//Ax+By = C -> -Bx+Ay = D
public Line perpendicular(){
if(isSegment){
float[] midpoint = GeoUtil.midpoint(X, Y);
return new Line(-this.B, this.A, midpoint);
} else {
return new Line(-this.B, this.A, 0);
}
}
public Line perpendicular(float[] point){
return new Line(-this.B, this.A, point);
}
public float[] reflection(float[] point){
Line perpendicular = perpendicular(point);
float[] intersection = intersection(perpendicular);
float[] reflection = new float[2]; //intersection - (point - intersection).
reflection[0] = 2 * intersection[0] - point[0];
reflection[1] = 2 * intersection[1] - point[1];
return reflection;
}
}