// Drawing.java // Class that stores a drawing as a list of Shape objects. // Written by THC for CS 5 HW 3. // Greatly modified by Scot Drysdale for VoronoiTool import java.util.ArrayList; import java.util.Iterator; import java.awt.*; import javax.swing.*; public class Drawing { private ArrayList shapes; // the ordered list of Shape objects private Drawable tempShape; // Hold the shape being constructed private boolean drawVD; // Draw VD only when true private boolean isClosestVD; // Indicates closest VD is to be drawn private final static Color[] standardColors = {Color.red, Color.blue, Color.green, Color.magenta, Color.orange, Color.yellow, Color.pink, Color.lightGray, Color.gray}; private int colorCount; // Number of colors assigned so far private Metric currentMetric; // Metric to be used for drawing VD private JPanel panel; // used to get the size of the canvas // Constructor creates an empty list of Shape objects. public Drawing(JPanel p) { shapes = new ArrayList(); panel = p; reset(); } // Reset the diagram to empty public void reset() { shapes.clear(); colorCount = 0; drawVD = false; tempShape = null; } // Return the height of the drawing in pixels public int getHeight() { return panel.getHeight() - 1; } // Return the width of the drawing in pixels public int getWidth() { return panel.getWidth() - 1; } // Set the drawVD variable public void setDrawVD() { drawVD = true; } // Set the currrent metric public void setMetric(Metric m) { currentMetric = m; } // set tempShape public void setTempShape(Drawable s) { tempShape = s; } // Add a Shape to the list. public void add(Shape s) { if(colorCount < standardColors.length) { s.setColor(standardColors[colorCount]); colorCount++; } else s.setColor(randomColor()); shapes.add(s); } // Creates a random color not too close to black public Color randomColor() { return new Color(randomColorValue(), randomColorValue(), randomColorValue()); } // Returns a random number less than 256 which is not close to 0 public int randomColorValue() { return (int) (Math.random()*200 + 56); } // Have each Shape in the list draw itself. public void draw(Graphics page) { if(drawVD) { drawVoronoi(page); drawVD = false; // Shouldn't draw it when do new command } page.setColor(Color.black); for (Shape s: shapes) s.draw(page); // Draw the temp shape, if there is one. if(tempShape != null) { page.setColor(Color.red); tempShape.draw(page); } } // Draw all pixels in the Voronoi diagram in correct color. public void drawVoronoi(Graphics page) { double closeFarFactor; if(isClosestVD) closeFarFactor = 1; else closeFarFactor = -1; if(shapes.size() > 0) for(int x = 0; x < getWidth(); x++) for(int y = 0; y < getHeight(); y++) { Shape s = getNearest(shapes, x, y, currentMetric, closeFarFactor); page.setColor(s.getColor()); page.drawRect(x, y, 1, 1); } } // Find nearest shape in shapes to p, using currentMetric to measure. // metricFactor is 1 for closest-type, -1 for farthest-type diagrams. // In case of tie, return one at random. (Leads to mixed colors in // two-dimensional regions.) // Precondition: shapes() > 0 private static Shape getNearest(ArrayList shapes, double x, double y, Metric myMetric, double metricFactor) { ArrayList minShapes = new ArrayList(); minShapes.add(shapes.get(0)); double minDist = myMetric.distance(minShapes.get(0), x, y) * metricFactor; for(int j = 1; j < shapes.size(); j++) { double newDist = myMetric.distance(shapes.get(j), x, y) * metricFactor; if(Math.abs(newDist - minDist) < .00000000001) minShapes.add(shapes.get(j)); else if(newDist < minDist) { // Found new min, so start list of equals over minDist = newDist; minShapes.clear(); minShapes.add(shapes.get(j)); } } return minShapes.get((int)(Math.random() * minShapes.size())); } // Return a reference to the closest Shape in the drawing to p. // If no Shape is near enough to p, return null. public Shape getCloseShape(Point p) { final int TOLERANCE = 9; Shape closest = null; double minDist = Double.MAX_VALUE; for (Shape s: shapes) { double dist = s.euclideanSq(p); if (dist < minDist) { closest = s; minDist = dist; } } if (minDist < TOLERANCE) return closest; else return null; } // Given a reference to a Shape, remove it from the drawing if it's there. public void remove(Shape s) { shapes.remove(s); } // Given a Rect, remove all Shapes that lie entirely within this Rect public void removeInRect(Rect r) { Iterator itr = shapes.iterator(); while(itr.hasNext()) { if(itr.next().isContained(r)) itr.remove(); } } // Set value of isClosestVD to b public void setClosest(boolean b) { isClosestVD = b; } }