package java.awt.geom;
import java.awt.Rectangle;
import java.awt.Shape;
/**
* An abstract class representing a line in two dimensional space
*
* @author Lawrie Griffiths
*
*/
public abstract class Line2D implements Shape, Cloneable {
/**
* A line in 2D space using float coordinates
*/
public static class Float extends Line2D {
/**
* The x coordinate of the start of the line
*/
public float x1;
/**
* The y coordinate of the start of the line
*/
public float y1;
/**
* The x coordinate of the end of the line
*/
public float x2;
/**
* The y coordinate of the end of the line
*/
public float y2;
/**
* Creates a zero length line at (0,0)
*/
public Float() {};
/**
* Create a line from (x1,y1) to (x2,y2)
*
* @param x1 the x coordinate of the start of the line
* @param y1 the y coordinate of the start of the line
* @param x2 the x coordinate of the end of the line
* @param y2 the y coordinate of the end of the line
*/
public Float(float x1, float y1, float x2, float y2) {
setLine(x1, y1, x2, y2);
}
/**
* Set the float coordinates of the start and end of the line
*
* @param x1 the x coordinate of the start of the line
* @param y1 the y coordinate of the start of the line
* @param x2 the x coordinate of the end of the line
* @param y2 the y coordinate of the end of the line
*/
public void setLine(float x1, float y1, float x2, float y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
/**
* Get the bounds of the line as a Rectangle2D
*/
public Rectangle2D getBounds2D() {
float x, y, w, h;
if (x1 < x2) {
x = x1;
w = x2 - x1;
} else {
x = x2;
w = x1 - x2;
}
if (y1 < y2) {
y = y1;
h = y2 - y1;
} else {
y = y2;
h = y1 - y2;
}
return new Rectangle2D.Float(x, y, w, h);
}
@Override
public double getX1() {
return (double) x1;
}
@Override
public double getY1() {
return (double) y1;
}
@Override
public Point2D getP1() {
return new Point2D.Float(x1, y1);
}
@Override
public double getX2() {
return (double) x2;
}
@Override
public double getY2() {
return (double) y2;
}
@Override
public Point2D getP2() {
return new Point2D.Float(x2, y2);
}
@Override
public void setLine(double x1, double y1, double x2, double y2) {
this.x1 = (float) x1;
this.y1 = (float) y1;
this.x2 = (float) x2;
this.y2 = (float) y2;
}
}
/**
* A line in 2D space using float coordinates
*/
public static class Double extends Line2D {
/**
* the x coordinate of the start of the line
*/
public double x1;
/**
* The y coordinate of the sztart of the line
*/
public double y1;
/**
* The x coordinate of the end of the line
*/
public double x2;
/**
* The y coordinate of the start of the line
*/
public double y2;
/**
* Create a zero length line at (0,0) with double coordinates
*/
public Double() {};
/**
* Create a line from (x1,y1) to (x2,y2) with double coordinate
*
* @param x1 the x coordinate of the start of the line
* @param y1 the y coordinate of the start of the line
* @param x2 the x coordinate of the end of the line
* @param y2 the y coordinate of the end of the line
*/
public Double(double x1, double y1, double x2, double y2) {
setLine(x1, y1, x2, y2);
}
@Override
public double getX1() {
return x1;
}
@Override
public double getY1() {
return y1;
}
@Override
public Point2D getP1() {
return new Point2D.Double(x1, y1);
}
@Override
public double getX2() {
return x2;
}
@Override
public double getY2() {
return y2;
}
@Override
public Point2D getP2() {
return new Point2D.Double(x2, y2);
}
@Override
public void setLine(double x1, double y1, double x2, double y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
/**
* Get the bounds of the line as a Rectangle2D
*/
public Rectangle2D getBounds2D() {
double x, y, w, h;
if (x1 < x2) {
x = x1;
w = x2 - x1;
} else {
x = x2;
w = x1 - x2;
}
if (y1 < y2) {
y = y1;
h = y2 - y1;
} else {
y = y2;
h = y1 - y2;
}
return new Rectangle2D.Double(x, y, w, h);
}
}
/**
* This is an abstract class that cannot be instantiated: use Line2D.Float or Line2D.Double.
*/
protected Line2D() {
}
/**
* Get the x coordinate of the start of the line
*
* @return the x coordinate as a double
*/
public abstract double getX1();
/**
* Get the y coordinate of the start of the line
*
* @return the y coordinate as a double
*/
public abstract double getY1();
/**
* Get the start point of the line as a Point2D
*
* @return the Point2D
*/
public abstract Point2D getP1();
/**
* Get the x coordinate of the end of the line
*
* @return the x coordinate as a double
*/
public abstract double getX2();
/**
* Get the y coordinate of the end of the line
*
* @return the y coordinate as a double
*/
public abstract double getY2();
/**
* Get the end point of the line as a Point2D
*
* @return the Point2D
*/
public abstract Point2D getP2();
/**
* Sets the end points of the line using double coordinates.
*
* @param x1 the x coordinate of the start point
* @param y1 the y coordinate of the start point
* @param x2 the x coordinate of the end point
* @param y2 the y coordinate of the end point
*/
public abstract void setLine(double x1, double y1, double x2, double y2);
/**
* Sets the end points of the line from a given start and end point
* @param p1 the start point
* @param p2 the end point
*/
public void setLine(Point2D p1, Point2D p2) {
setLine(p1.getX(), p1.getY(), p2.getX(), p2.getY());
}
/**
* Set the end points of a line to the same as a given line
*
* @param line the given line
*/
public void setLine(Line2D line) {
setLine(line.getX1(), line.getY1(), line.getX2(), line.getY2());
}
public boolean contains(double x, double y) {
return false;
}
public boolean contains(Point2D p) {
return false;
}
public boolean contains(double x, double y, double w, double h) {
return false;
}
public boolean contains(Rectangle2D r) {
return false;
}
public boolean intersects(double x, double y, double w, double h) {
return intersects(new Rectangle2D.Double(x, y, w, h));
}
/**
* Test if this line intersects a given line
*
* @param x1 the x coordinate of the start of the given line
* @param y1 the y coordinate of the start of the given line
* @param x2 the x coordinate of the end of the given line
* @param y2 the y coordinate of the end of the given line
* @return true iff the lines intersect
*/
public boolean intersectsLine(double x1, double y1, double x2, double y2) {
return linesIntersect(x1, y1, x2, y2,
getX1(), getY1(), getX2(), getY2());
}
/**
* Tests if this line intersects a given line
*
* @param l the given line
* @return true iff the lines intersect
*/
public boolean intersectsLine(Line2D l) {
return linesIntersect(l.getX1(), l.getY1(), l.getX2(), l.getY2(),
getX1(), getY1(), getX2(), getY2());
}
/**
* Test if one line intersects another line
*
* @param x1 the x coordinate of the start of the first line
* @param y1 the y coordinate of the start of the first line
* @param x2 the x coordinate of the end of the first line
* @param y2 the y coordinate of the end of the first line
* @param x3 the x coordinate of the start of the second line
* @param y3 the y coordinate of the start of the second line
* @param x4 the x coordinate of the end of the second line
* @param y4 the y coordinate of the end of the second line
* @return true iff the lines intersect
*/
public static boolean linesIntersect(
double x1, double y1,
double x2, double y2,
double x3, double y3,
double x4, double y4)
{
return ((relativeCCW(x1, y1, x2, y2, x3, y3) *
relativeCCW(x1, y1, x2, y2, x4, y4) <= 0) &&
(relativeCCW(x3, y3, x4, y4, x1, y1) *
relativeCCW(x3, y3, x4, y4, x2, y2) <= 0));
}
public Rectangle getBounds() {
return getBounds2D().getBounds();
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new RuntimeException();
}
}
/**
* Returns an indicator of where the specified point
* lies with respect to the line
*
* @param x1 the x coordinate of the start of the line
* @param y1 the y coordinate of the start of the line
* @param x2 the x coordinate of the end of the line
* @param y2 the y coordinate of the end of the line
* @param px the x coordinate of the specified point
* @param py the y coordinate of the specified point
* @return 0 iff the point is on the line else 1 or -1 depending
* on whether the point in to the left or ahead of the line, or to the right or behind
* the line segment
*/
public static int relativeCCW(
double x1, double y1,
double x2, double y2,
double px, double py)
{
double tx = x2 - x1;
double ty = y2 - y1;
double tpx = px - x1;
double tpy = py - y1;
double ccw = tpx * ty - tpy * tx;
if (ccw == 0) {
ccw = tpx * tx + tpy * ty;
if (ccw > 0) {
tpx -= tx;
tpy -= ty;
ccw = tpx * tx + tpy * ty;
if (ccw < 0) ccw = 0;
}
}
return (ccw < 0) ? -1 : ((ccw > 0) ? 1 : 0);
}
/**
* Returns an indicator of where the specified point
* lies with respect to the line
*
* @param p the specified point
* @return 0 iff the point is on the line else 1 or -1 depending
* on whether the point in to the left or ahead of the line, or to the right or behind
* the line segment
*/
public int relativeCCW(Point2D p) {
return relativeCCW(getX1(), getY1(), getX2(), getY2(),
p.getX(), p.getY());
}
/**
* Returns an indicator of where the specified point
* lies with respect to the line.
*
* @param px the x coordinate of the specified point
* @param py the y coordinate of the specified point
* @return 0 iff the point is on the line else 1 or -1 depending
* on whether the point in to the left or ahead of the line, or to the right or behind
* the line segment
*/
public int relativeCCW(double px, double py) {
return relativeCCW(getX1(), getY1(), getX2(), getY2(), px, py);
}
public boolean intersects(Rectangle2D r) {
return r.intersectsLine(getX1(), getY1(), getX2(), getY2());
}
}