GraphOutline.java

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;
    }
}
Valid HTML 4.01 Valid CSS