package edu.hawaii.ics.yucheng;
import java.awt.Graphics2D;
import java.util.ArrayList;
/**
* A class that draws an outline of a graph and its obstacles.
*/
class GraphOutline {
/**
* A class that draws an arc.
*/
private final class ArcOperation extends Operation {
/** The angle of the arc. */
public int arcAngle;
/** The height of the arc. */
public int height;
/** The starting angle of the arc. */
public int startAngle;
/** The width of the arc. */
public int width;
/** The horizontal location. */
public int x;
/** The vertical location. */
public int y;
/**
* Initializes a new instance of the ArcOperation class.
*/
public ArcOperation() {
super();
}
/**
* Draws the arc.
*
* @param g The graphics object.
*/
@Override
public void draw(final Graphics2D g) {
assert null != g;
g.drawArc(x, y, width, height, startAngle, arcAngle);
}
}
/**
* A class that draws a line.
*/
private final class LineOperation extends Operation {
/** The first horizontal location. */
public int x1;
/** The second horizontal location. */
public int x2;
/** The first vertical location. */
public int y1;
/** The second horizontal location. */
public int y2;
/**
* Initializes a new instance of the LineOperation class.
*/
public LineOperation() {
super();
}
/**
* Draws the line.
*
* @param g The graphics object.
*/
@Override
public void draw(final Graphics2D g) {
assert null != g;
g.drawLine(x1, y1, x2, y2);
}
}
/**
* A base class for drawing operations performed by this class.
*/
private abstract class Operation {
/**
* Initializes a new instance of the Operation class.
*/
protected Operation() {
// Do nothing.
}
/**
* Draws to the graphics object.
*
* @param g The graphics object.
*/
public abstract void draw(final Graphics2D g);
}
/** The graph for which the outline is drawn. */
private final Graph myGraph;
/** The collection of drawing operations. */
private final ArrayList<Operation> myOperations = new ArrayList<Operation>();
/**
* Initializes a new instance of the GraphOutline class.
*
* @param graph The graph.
*/
public GraphOutline(final Graph graph) {
if (graph == null)
throw new NullPointerException("graph");
myGraph = graph;
for (int y = 0; y < graph.height; y++)
for (int x = 0; x < graph.width; x++)
trace(x, y);
}
/**
* Draws the graph outline.
*
* @param g The graphics object.
*/
public void draw(final Graphics2D g) {
if (g == null)
throw new NullPointerException("g");
for (final Operation operation : myOperations)
operation.draw(g);
}
/**
* Returns true if a location in the graph is an inner, bottom left point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an inner, bottom left point.
*/
private boolean isInnerBottomLeft(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x, y + 1)
&& !isObstacle(x - 1, y + 1);
}
/**
* Returns true if a location in the graph is an inner, bottom right point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an inner, bottom right point.
*/
private boolean isInnerBottomRight(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x, y + 1)
&& !isObstacle(x + 1, y + 1);
}
/**
* Returns true if a location in the graph is an inner, top left point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an inner, top left point.
*/
private boolean isInnerTopLeft(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x, y - 1)
&& !isObstacle(x - 1, y - 1);
}
/**
* Returns true if a location in the graph is an inner, top right point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an inner, top right point.
*/
private boolean isInnerTopRight(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x, y - 1)
&& !isObstacle(x + 1, y - 1);
}
/**
* Returns true if a location in the graph is an obstacle or is outside the
* "edges" of the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an obstacle or is outside the "edges" of
* the graph.
*/
private boolean isObstacle(final int x, final int y) {
return !isValid(x, y) || myGraph.isObstacle(x, y);
}
/**
* Returns true if a location in the graph is an outer, bottom left point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an outer, bottom left point.
*/
private boolean isOuterBottomLeft(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x - 1, y)
&& isObstacle(x - 1, y + 1) && isObstacle(x, y + 1);
}
/**
* Returns true if a location in the graph is an outer, bottom right point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an outer, bottom right point.
*/
private boolean isOuterBottomRight(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x + 1, y)
&& isObstacle(x + 1, y + 1) && isObstacle(x, y + 1);
}
/**
* Returns true if a location in the graph is an outer, top left point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an outer, bottom right point.
*/
private boolean isOuterTopLeft(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x - 1, y)
&& isObstacle(x - 1, y - 1) && isObstacle(x, y - 1);
}
/**
* Returns true if a location in the graph is an outer, top right point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is an outer, top right point.
*/
private boolean isOuterTopRight(final int x, final int y) {
return !isObstacle(x, y) && isObstacle(x + 1, y)
&& isObstacle(x + 1, y - 1) && isObstacle(x, y - 1);
}
/**
* Returns true if a location is within the bounds of the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*
* @return True if the location is within the bounds of the graph.
*/
private boolean isValid(final int x, final int y) {
return x >= 0 && y >= 0 && x < myGraph.width && y < myGraph.height;
}
/**
* Traces the graph at a specified point.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private void trace(final int x, final int y) {
if (myGraph.isObstacle(x, y))
return;
traceTop(x, y);
traceLeft(x, y);
traceBottom(x, y);
traceRight(x, y);
}
/**
* Traces the bottom of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private void traceBottom(final int x, final int y) {
if (isObstacle(x, y) || !isObstacle(x, y + 1))
return;
final int dx1 = traceOuterBottomLeft(x, y) + traceInnerBottomLeft(x, y);
final int dx2 = traceOuterBottomRight(x, y) + traceInnerBottomRight(x, y);
final LineOperation op = new LineOperation();
op.x1 = x1(x) + dx1;
op.y1 = y2(y);
op.x2 = x2(x) - dx2;
op.y2 = y2(y);
myOperations.add(op);
}
/**
* Traces the inner, bottom left of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceInnerBottomLeft(final int x, final int y) {
if (!isInnerBottomLeft(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x1(x);
op.y = y2(y);
op.width = 40;
op.height = 40;
op.startAngle = 90;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the inner, bottom right of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceInnerBottomRight(final int x, final int y) {
if (!isInnerBottomRight(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x2(x) - 40;
op.y = y2(y);
op.width = 40;
op.height = 40;
op.startAngle = 0;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the inner, top left of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceInnerTopLeft(final int x, final int y) {
if (!isInnerTopLeft(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x1(x);
op.y = y1(y) - 40;
op.width = 40;
op.height = 40;
op.startAngle = 180;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the inner, top right of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceInnerTopRight(final int x, final int y) {
if (!isInnerTopRight(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x2(x) - 40;
op.y = y1(y) - 40;
op.width = 40;
op.height = 40;
op.startAngle = 270;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the left of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private void traceLeft(final int x, final int y) {
if (isObstacle(x, y) || !isObstacle(x - 1, y))
return;
int dy1 = 0;
if (isInnerBottomRight(x - 1, y - 1) || isOuterTopLeft(x, y))
dy1 += 20;
int dy2 = 0;
if (isOuterBottomLeft(x, y) || isInnerTopRight(x - 1, y + 1))
dy2 += 20;
final LineOperation op = new LineOperation();
op.x1 = x1(x);
op.y1 = y1(y) + dy1;
op.x2 = x1(x);
op.y2 = y2(y) - dy2;
myOperations.add(op);
}
/**
* Traces the outer, bottom left of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceOuterBottomLeft(final int x, final int y) {
if (!isOuterBottomLeft(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x1(x);
op.y = y2(y) - 40;
op.width = 40;
op.height = 40;
op.startAngle = 180;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the outer, bottom right of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceOuterBottomRight(final int x, final int y) {
if (!isOuterBottomRight(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x2(x) - 40;
op.y = y2(y) - 40;
op.width = 40;
op.height = 40;
op.startAngle = 270;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the outer, top left of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceOuterTopLeft(final int x, final int y) {
if (!isOuterTopLeft(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x1(x);
op.y = y1(y);
op.width = 40;
op.height = 40;
op.startAngle = 90;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the outer, bottom right of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private int traceOuterTopRight(final int x, final int y) {
if (!isOuterTopRight(x, y))
return 0;
final ArcOperation op = new ArcOperation();
op.x = x2(x) - 40;
op.y = y1(y);
op.width = 40;
op.height = 40;
op.startAngle = 0;
op.arcAngle = 90;
myOperations.add(op);
return 20;
}
/**
* Traces the right of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private void traceRight(final int x, final int y) {
if (isObstacle(x, y) || !isObstacle(x + 1, y))
return;
int dy1 = 0;
if (isInnerBottomLeft(x + 1, y - 1) || isOuterTopRight(x, y))
dy1 += 20;
int dy2 = 0;
if (isOuterBottomRight(x, y) || isInnerTopLeft(x + 1, y + 1))
dy2 += 20;
final LineOperation op = new LineOperation();
op.x1 = x2(x);
op.y1 = y1(y) + dy1;
op.x2 = x2(x);
op.y2 = y2(y) - dy2;
myOperations.add(op);
}
/**
* Traces the top of a point in the graph.
*
* @param x The x coordinate.
*
* @param y The y coordinate.
*/
private void traceTop(final int x, final int y) {
if (isObstacle(x, y) || !isObstacle(x, y - 1))
return;
final int dx1 = traceOuterTopLeft(x, y) + traceInnerTopLeft(x, y);
final int dx2 = traceOuterTopRight(x, y) + traceInnerTopRight(x, y);
final LineOperation op = new LineOperation();
op.x1 = x1(x) + dx1;
op.y1 = y1(y);
op.x2 = x2(x) - dx2;
op.y2 = y1(y);
myOperations.add(op);
}
/**
* Returns the scaled horizontal location for the left location of a cell.
*
* @param x The x coordinate.
*/
private int x1(final int x) {
return x * 100;
}
/**
* Returns the scaled horizontal location for the right location of a cell.
*
* @param x The x coordinate.
*/
private int x2(final int x) {
return x * 100 + 100;
}
/**
* Returns the scaled vertical location for the top location of a cell.
*
* @param y The y coordinate.
*/
private int y1(final int y) {
return y * 100;
}
/**
* Returns the scaled vertical location for the bottom location of a cell.
*
* @param y The y coordinate.
*/
private int y2(final int y) {
return y * 100 + 100;
}
}