package com.bbn.openmap.omGraphics.awt; import java.awt.Graphics; import java.awt.Shape; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** * The ShapeDecorator class : in charge of drawing repeatedly several * stored decorations along a path (a polyline or a complex shape) * * @author Eric LEPICIER * @version 26 juil. 2002 */ public class ShapeDecorator implements Revertable { /** * The list of decorations (instances of ShapeDecoration) */ private List<ShapeDecoration> decorations = new ArrayList<ShapeDecoration>(); /** * The flatness used for Shape.getPathIterator() */ public static double FLATNESS = 0.1; /** * Default constructor */ public ShapeDecorator() {} /** * Returns the decorations. * * @return List the list of decorations */ public List<ShapeDecoration> getDecorations() { return decorations; } /** * Inserts a Decoration. * * @param index the index where to insert the new decoration * @param decoration the new decoration */ public void insertDecoration(int index, ShapeDecoration decoration) { decorations.add(index, decoration); } /** * Adds a Decoration at the end of the list. * * @param decoration the new decoration */ public void addDecoration(ShapeDecoration decoration) { decorations.add(decoration); } /** * Removes a Decoration. * * @param index the index of the Decoration to be removed * @return ShapeDecoration the removed Decoration */ public ShapeDecoration removeDecoration(int index) { return decorations.remove(index); } /** * Removes a Decoration. * * @param decoration the decoration to remove * @return boolean true if it was removed */ public boolean removeDecoration(ShapeDecoration decoration) { return decorations.remove(decoration); } /** * Reverts all the decorations * * @see com.bbn.openmap.omGraphics.awt.Revertable#revert() */ public void revert() { for (ShapeDecoration shapeDecoration : decorations) { shapeDecoration.revert(); } } /** * Draws a decorated shape * * @param g the Graphics to use * @param s the shape to render */ public void draw(Graphics g, Shape s) { if (decorations.isEmpty()) return; PathIterator pi = s.getPathIterator(null, FLATNESS); int segType; double[] segCoords = new double[6]; LinkedList<Point2D> points = new LinkedList<Point2D>(); Point2D firstPoint = null; Point2D point; // split path in polylines do { segType = pi.currentSegment(segCoords); point = new Point2D.Double(segCoords[0], segCoords[1]); switch (segType) { case PathIterator.SEG_MOVETO: if (firstPoint == null) firstPoint = point; if (!points.isEmpty()) { // draw decorations for the previous polyline draw(g, points); } // init a new polyline points.clear(); points.add(point); break; case PathIterator.SEG_LINETO: points.add(point); break; case PathIterator.SEG_CLOSE: points.add(firstPoint); break; } pi.next(); } while (!pi.isDone()); // draw decorations for the last poly if (!points.isEmpty()) { draw(g, points); } } /** * Draws a decorated polyline * * @param g the Graphics to use * @param xcoords array of x floating coordinates * @param ycoords array of y floating coordinates */ public void draw(Graphics g, float xcoords[], float[] ycoords) { LinkedList<Point2D> points = new LinkedList<Point2D>(); for (int i = 0; i < xcoords.length; i++) { points.add(new Point2D.Double(xcoords[i], ycoords[i])); } draw(g, points); } /** * Draws a decorated polyline * * @param g the Graphics to use * @param xcoords array of x integer coordinates * @param ycoords array of y integer coordinates */ public void draw(Graphics g, int xcoords[], int[] ycoords) { LinkedList<Point2D> points = new LinkedList<Point2D>(); for (int i = 0; i < xcoords.length; i++) points.add(new Point2D.Double(xcoords[i], ycoords[i])); draw(g, points); } /** * Draws a decorated polyline * * @param g the Graphics to use * @param points array of points */ public void draw(Graphics g, Point2D[] points) { LinkedList<Point2D> pointlist = new LinkedList<Point2D>(); for (int i = 0; i < points.length; i++) pointlist.add(points[i]); draw(g, pointlist); } /** * Draws a decorated polyline Calls ShapeDecoration.draw(...) for * each decoration on an subsetted polyline with the same length * than the decoration, cycling until all the path is consumed. * * @param g the Graphics to use * @param points array of points (instances of Point2D) */ protected void draw(Graphics g, LinkedList<Point2D> points) { if (decorations.isEmpty()) throw new NullPointerException("No decorations"); Iterator<ShapeDecoration> decorationIterator = decorations.listIterator(); LinkedList<Point2D> polysegment = new LinkedList<Point2D>(); Point2D[] point2DArrayType = new Point2D.Double[1]; while (!points.isEmpty()) { if (!decorationIterator.hasNext()) { decorationIterator = decorations.listIterator(); } ShapeDecoration decor = decorationIterator.next(); boolean complete = LineUtil.retrievePoints(decor.getLength(), points, polysegment); // drawing is delegated to the decoration decor.draw(g, (Point2D[]) polysegment.toArray(point2DArrayType), complete); } } }