// Implements a simple line class. // (c) 1997,1998 duane a. bailey package element; /** * A line segment object. * * @version $Id: Line.java,v 2.2 1999/08/05 16:18:01 bailey Exp bailey $ * @author duane a. bailey */ public class Line implements Drawable { /** * Endpoints of the line segment. When drawing, we always * draw the line segment from (x0,y0) to (x1,y1), where * x0 < x1 or (x0 = x1 and y0 <= y1). The reason: most line * drawing mechanisms will draw one of the points and not * the other. This avoids many silly issues. */ private int x0, y0; // ordered private int x1, y1; /** * Construct a trivial line segment at the origin. */ public Line() // post: constructs a trivial line segment at origin { this(0,0,0,0); } /** * Construct a line segment from another. * @param l another line segment. */ public Line(Line l) // pre: l is a valid line segment // post: this is a copy of l { x0 = l.x0; x1 = l.x1; y0 = l.y0; y1 = l.y1; } /** * Construct a line segment from (left,top) to (right,bottom) of * a rectangle. * @param r the rectangle. */ public Line(Rect r) // post: constructs a line from a rectangle { x0 = r.left(); x1 = r.right(); y0 = r.top(); y1 = r.bottom(); } /** * Construct a line segment from the explicit points. * @param x0 one x coordinate * @param y0 one y coordinate * @param x1 other x coordinate * @param y1 other y coordinate */ public Line(int x0, int y0, int x1, int y1) // pre: w >= 0, h >= 0 // post: constructs rectangle with top left at (x,y), // width w, height h { if ((x0 < x1) || ((x0 == x1) && (y0 <= y1))) { this.x0 = x0; this.x1 = x1; this.y0 = y0; this.y1 = y1; } else { this.x0 = x1; this.x1 = x0; this.y0 = y1; this.y1 = y0; } } /** * Construct a line segment from its two endpoints. * @param p one endpoint * @param q the other endpoint */ public Line(Pt p, Pt q) // pre: p and q are valid points // post: constructs a line segment from the two endpoints { this(p.x(),p.y(),q.x(),q.y()); } /** * Return the left-most coordinate of the segment. */ public int left() // post: returns the left-most coordinate of the segment { return x0; } /** * Return the right-most coordinate of the segment */ public int right() // post: returns the right-most coordinate of the segment { return x1; } /** * Return the top-most coordinate of the segment. */ public int top() // post: returns the top-most coordinate of the segment { return Math.min(y0,y1); } /** * Return the bottom-most coordinate of the segment. */ public int bottom() // post: returns the bottom-most coordinate of the segment { return Math.max(y0,y1); } /** * Move line segment so that left side is at x. * @param x new left side of line segment */ public void left(int x) // post: adjusts line so that it falls to the right of x { int dx = x-left(); x0 += dx; x1 += dx; } /** * Move line segment so that right side is at x. * @param x new right side of the line segment */ public void right(int x) // post: adjusts line so that it falls to the left of x { int dx = x-right(); x0 += dx; x1 += dx; } /** * Move the line segment so that top is at y. * @param y new top side of the line segment. */ public void top(int y) // post: adjusts line so that it falls below y { int dy = y-top(); y0 += dy; y1 += dy; } /** * Move the line segment so that bottom is at y. * @param y new bottom side of the line segment */ public void bottom(int y) // post: adjusts line so that it falls above y { int dy = y-bottom(); y0 += dy; y1 += dy; } /** * Determine the horizontal span of the line segment * @return the horizontal span of the line segment */ public int width() // post: returns the horizontal distance between endpoints { return x1-x0; } /** * Determine the vertical span of the line segment * @return the vertical span of the line segment */ public int height() // post: returns the vertical distance between endpoints { return Math.abs(y0-y1); } /** * Determine the midpoint of the line segment. * @return the midpoint of the line segment. */ public Pt center() // post: returns the midpoint of the line segment { return new Pt((x0+x1)/2,(y0+y1)/2); } /** * Adjust line so that midpoint falls at p. * @param p the new midpoint of the line. */ public void center(Pt p) // pre: p is the desired midpoint of line // post: the line is moved to make p the midpoint { Pt q = center(); left(left()+(p.x()-q.x())); top(top()+(p.y()-q.y())); } /** * Returns one endpoint of the line. */ public Pt here() // post: returns one endpoint of the line { return new Pt(x0,y0); } /** * Returns other endpoint of the line. */ public Pt there() // post: returns another endpoint of the line { return new Pt(x1,y1); } /** * Determine if a value falls between two others. * @return true if low <= x <= range */ protected static boolean within(int x, int low, int range) { return (low <= x) && (x <= (low+range)); } /** * Return true if the point p is close to the line segment * @param p the point in question * @return true if p is on the line segment */ public boolean contains(Pt p) // pre: p is not null // post: returns true if p lies on line segment { if (height() == 0) { return (p.y() == top()) && Line.within(p.x(),left(),width()); } if (width() == 0) { return (p.x() == left()) && Line.within(p.y(),top(),height()); } if (!Line.within(p.x(),left(),width())) return false; int y = (y1-y0)*(p.x()-x0)/(x1-x0)+y0; return y == p.y(); } /** * Draw the line on the drawing window d in current mode. * @param d the target window d * @see element.DrawingWindow#draw * @see element.DrawingWindow#invertMode * @see element.DrawingWindow#paintMode */ public void fillOn(DrawingWindow d) // pre: d is a valid drawing window // post: line is drawn on window d in the current mode { d.fillLine(x0,y0,x1,y1); } /** * Erase the line from the drawing window d in current mode. * @param d the target window d * @see element.DrawingWindow#clear * @see element.DrawingWindow#invertMode * @see element.DrawingWindow#paintMode */ public void clearOn(DrawingWindow d) // pre: d is a valid drawing window // post: line is erased from window d in the current mode { d.clearLine(x0,y0,x1,y1); } /** * Draw the line on the drawing window d in current mode. * @param d the target window d * @see element.DrawingWindow#draw * @see element.DrawingWindow#invertMode * @see element.DrawingWindow#paintMode */ public void drawOn(DrawingWindow d) // pre: d is a valid drawing window // post: line is drawn on window d in the current mode { d.drawLine(x0,y0,x1,y1); } /** * Returns hash code for the line segment. * * @return hash code for the line segment */ public int hashCode() // post: returns suitable hash code { return x0+y0+x1+y1; } /** * Returns true if two line segments are equal * * @param other the other line segment * @return true if the segments have equal value */ public boolean equals(Object other) // pre: other is a valid line segment // post: returns true if two rects are equal valued { Line that = (Line)other; return (this.x0 == that.x0) && (this.y0 == that.y0) && (this.x1 == that.x1) && (this.y1 == that.y1); } /** * Return a copy of this line segment. * * @return copy of this line segment. */ public Object clone() // post: returns a distinct copy of the line segment { return new Line(this); } /** * Return a string representation of the line segment * * @return */ public String toString() // post: returns a string representation of the line segment { return ""; } }