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; } }