package framework.spacial;
import java.io.IOException;
import main.L;
import org.newdawn.slick.geom.Vector2f;
import framework.io.CustomInputStream;
import framework.io.CustomOutputStream;
import framework.io.Writeable;
public class Line implements Writeable {
private Vector2f from;
private Vector2f to;
public Line(Vector2f from, Vector2f to){
this.from = from;
this.to = to;
}
public Line(CustomInputStream in) throws IOException{
this.from = in.readVector();
this.to = in.readVector();
}
public Line(Vector2f from, float toX, float toY){
this(from, new Vector2f(toX, toY));
}
public Line(float fromX, float fromY, Vector2f to){
this(new Vector2f(fromX, fromY), to);
}
public Line(float fromX,float fromY, float toX,float toY){
this(new Vector2f(fromX, fromY), new Vector2f(toX, toY));
}
public Vector2f getIntersectionWith(Line otherLine){
return getLineLineIntersection(getFrom().getX(), getFrom().getY(), getTo().getX(), getTo().getY(), otherLine.getFrom().getX(), otherLine.getFrom().getY(), otherLine.getTo().getX(), otherLine.getTo().getY());
}
public boolean intersetsWith(Line otherLine){
return linesIntersect(getFrom().getX(), getFrom().getY(), getTo().getX(), getTo().getY(), otherLine.getFrom().getX(), otherLine.getFrom().getY(), otherLine.getTo().getX(), otherLine.getTo().getY());
}
public Vector2f getClosestPointTo(Vector2f p){
return getClosestPoint(from, to, p);
}
public boolean isOnLine(float tollerance, Vector2f point){
return point != null && getClosestPointTo(point).sub(point).length() <= tollerance;
}
public boolean isOnLine(Vector2f point){
return isOnLine(0.001f, point);
}
public float getShortestDistanceTo(Vector2f p){
return getClosestPointTo(p).sub(p).length();
}
@Override
public void writeToStream(CustomOutputStream out) throws IOException {
out.write(from);
out.write(to);
}
public Vector2f getFrom() {
return from.copy();
}
public void setFrom(Vector2f from) {
this.from = from;
}
public Vector2f getTo() {
return to.copy();
}
public void setTo(Vector2f to) {
this.to = to;
}
public Line copy(){
return new Line(from.copy(), to.copy());
}
public Line translate(Vector2f v){
from.add(v);
to.add(v);
return this;
}
public void rotate(float theta){
from.setTheta(from.getTheta() + theta);
to.setTheta(from.getTheta() + theta);
}
public void rotateAround(float theta, Vector2f centre){
VectorUtil.rotateAround(from,centre, theta);
VectorUtil.rotateAround(to,centre, theta);
}
public float getXWidth(){
if(from != null && to != null){
return Math.abs(from.getX() - to.getX());
}
return 0;
}
public float getYHeight(){
if(from != null && to != null){
return Math.abs(from.getY() - to.getY());
}
return 0;
}
public float getLength(){
return getTo().sub(getFrom()).length();
}
//NOT MY CODE:
public static boolean linesIntersect(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4){
// Return false if either of the lines have zero length
if (x1 == x2 && y1 == y2 ||
x3 == x4 && y3 == y4){
return false;
}
// Fastest method, based on Franklin Antonio's "Faster Line Segment Intersection" topic "in Graphics Gems III" book (http://www.graphicsgems.org/)
float ax = x2-x1;
float ay = y2-y1;
float bx = x3-x4;
float by = y3-y4;
float cx = x1-x3;
float cy = y1-y3;
float alphaNumerator = by*cx - bx*cy;
float commonDenominator = ay*bx - ax*by;
if (commonDenominator > 0){
if (alphaNumerator < 0 || alphaNumerator > commonDenominator){
return false;
}
}else if (commonDenominator < 0){
if (alphaNumerator > 0 || alphaNumerator < commonDenominator){
return false;
}
}
float betaNumerator = ax*cy - ay*cx;
if (commonDenominator > 0){
if (betaNumerator < 0 || betaNumerator > commonDenominator){
return false;
}
}else if (commonDenominator < 0){
if (betaNumerator > 0 || betaNumerator < commonDenominator){
return false;
}
}
if (commonDenominator == 0){
// This code wasn't in Franklin Antonio's method. It was added by Keith Woodward.
// The lines are parallel.
// Check if they're collinear.
float y3LessY1 = y3-y1;
float collinearityTestForP3 = x1*(y2-y3) + x2*(y3LessY1) + x3*(y1-y2); // see http://mathworld.wolfram.com/Collinear.html
// If p3 is collinear with p1 and p2 then p4 will also be collinear, since p1-p2 is parallel with p3-p4
if (collinearityTestForP3 == 0){
// The lines are collinear. Now check if they overlap.
if (x1 >= x3 && x1 <= x4 || x1 <= x3 && x1 >= x4 ||
x2 >= x3 && x2 <= x4 || x2 <= x3 && x2 >= x4 ||
x3 >= x1 && x3 <= x2 || x3 <= x1 && x3 >= x2){
if (y1 >= y3 && y1 <= y4 || y1 <= y3 && y1 >= y4 ||
y2 >= y3 && y2 <= y4 || y2 <= y3 && y2 >= y4 ||
y3 >= y1 && y3 <= y2 || y3 <= y1 && y3 >= y2){
return true;
}
}
}
return false;
}
return true;
}
public static Vector2f getLineLineIntersection(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
float det1And2 = det(x1, y1, x2, y2);
float det3And4 = det(x3, y3, x4, y4);
float x1LessX2 = x1 - x2;
float y1LessY2 = y1 - y2;
float x3LessX4 = x3 - x4;
float y3LessY4 = y3 - y4;
float det1Less2And3Less4 = det(x1LessX2, y1LessY2, x3LessX4, y3LessY4);
if (det1Less2And3Less4 == 0){
// the denominator is zero so the lines are parallel and there's either no solution (or multiple solutions if the lines overlap) so return null.
return null;
}
float x = (det(det1And2, x1LessX2,
det3And4, x3LessX4) /
det1Less2And3Less4);
float y = (det(det1And2, y1LessY2,
det3And4, y3LessY4) /
det1Less2And3Less4);
return new Vector2f(x, y);
}
protected static float det(float a, float b, float c, float d) {
return a * d - b * c;
}
private static Vector2f getClosestPoint(Vector2f pt1, Vector2f pt2, Vector2f p){
double u = ((p.getX()-pt1.getX())*(pt2.getX()-pt1.getX())+(p.getY()-pt1.getY())*(pt2.getY()-pt1.getY()))/(sqr(pt2.getX()-pt1.getX())+sqr(pt2.getY()-pt1.getY()));
if (u > 1.0)
return pt2.copy();
else if (u <= 0.0)
return pt1.copy();
else
return new Vector2f((int)(pt2.getX()*u+pt1.getX()*(1.0-u)+0.5), (int)(pt2.getY()*u+pt1.getY()*(1.0-u)+0.5));
}
private static double sqr(double x)
{
return x*x;
}
}