001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jfreechart/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * ---------------------------
028: * DefaultDrawingSupplier.java
029: * ---------------------------
030: * (C) Copyright 2003-2007, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): Jeremy Bowman;
034: *
035: * $Id: DefaultDrawingSupplier.java,v 1.6.2.4 2007/06/13 11:13:37 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 16-Jan-2003 : Version 1 (DG);
040: * 17-Jan-2003 : Added stroke method, renamed DefaultPaintSupplier
041: * --> DefaultDrawingSupplier (DG)
042: * 27-Jan-2003 : Incorporated code from SeriesShapeFactory, originally
043: * contributed by Jeremy Bowman (DG);
044: * 25-Mar-2003 : Implemented Serializable (DG);
045: * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
046: * ------------- JFREECHART 1.0.x ---------------------------------------------
047: * 13-Jun-2007 : Added fillPaintSequence (DG);
048: *
049: */
050:
051: package org.jfree.chart.plot;
052:
053: import java.awt.BasicStroke;
054: import java.awt.Color;
055: import java.awt.Paint;
056: import java.awt.Polygon;
057: import java.awt.Shape;
058: import java.awt.Stroke;
059: import java.awt.geom.Ellipse2D;
060: import java.awt.geom.Rectangle2D;
061: import java.io.IOException;
062: import java.io.ObjectInputStream;
063: import java.io.ObjectOutputStream;
064: import java.io.Serializable;
065: import java.util.Arrays;
066:
067: import org.jfree.chart.ChartColor;
068: import org.jfree.io.SerialUtilities;
069: import org.jfree.util.PublicCloneable;
070: import org.jfree.util.ShapeUtilities;
071:
072: /**
073: * A default implementation of the {@link DrawingSupplier} interface. All
074: * {@link Plot} instances have a new instance of this class installed by
075: * default.
076: */
077: public class DefaultDrawingSupplier implements DrawingSupplier,
078: Cloneable, PublicCloneable, Serializable {
079:
080: /** For serialization. */
081: private static final long serialVersionUID = -7339847061039422538L;
082:
083: /** The default fill paint sequence. */
084: public static final Paint[] DEFAULT_PAINT_SEQUENCE = ChartColor
085: .createDefaultPaintArray();
086:
087: /** The default outline paint sequence. */
088: public static final Paint[] DEFAULT_OUTLINE_PAINT_SEQUENCE = new Paint[] { Color.lightGray };
089:
090: /** The default fill paint sequence. */
091: public static final Paint[] DEFAULT_FILL_PAINT_SEQUENCE = new Paint[] { Color.white };
092:
093: /** The default stroke sequence. */
094: public static final Stroke[] DEFAULT_STROKE_SEQUENCE = new Stroke[] { new BasicStroke(
095: 1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL) };
096:
097: /** The default outline stroke sequence. */
098: public static final Stroke[] DEFAULT_OUTLINE_STROKE_SEQUENCE = new Stroke[] { new BasicStroke(
099: 1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL) };
100:
101: /** The default shape sequence. */
102: public static final Shape[] DEFAULT_SHAPE_SEQUENCE = createStandardSeriesShapes();
103:
104: /** The paint sequence. */
105: private transient Paint[] paintSequence;
106:
107: /** The current paint index. */
108: private int paintIndex;
109:
110: /** The outline paint sequence. */
111: private transient Paint[] outlinePaintSequence;
112:
113: /** The current outline paint index. */
114: private int outlinePaintIndex;
115:
116: /** The fill paint sequence. */
117: private transient Paint[] fillPaintSequence;
118:
119: /** The current fill paint index. */
120: private int fillPaintIndex;
121:
122: /** The stroke sequence. */
123: private transient Stroke[] strokeSequence;
124:
125: /** The current stroke index. */
126: private int strokeIndex;
127:
128: /** The outline stroke sequence. */
129: private transient Stroke[] outlineStrokeSequence;
130:
131: /** The current outline stroke index. */
132: private int outlineStrokeIndex;
133:
134: /** The shape sequence. */
135: private transient Shape[] shapeSequence;
136:
137: /** The current shape index. */
138: private int shapeIndex;
139:
140: /**
141: * Creates a new supplier, with default sequences for fill paint, outline
142: * paint, stroke and shapes.
143: */
144: public DefaultDrawingSupplier() {
145:
146: this (DEFAULT_PAINT_SEQUENCE, DEFAULT_FILL_PAINT_SEQUENCE,
147: DEFAULT_OUTLINE_PAINT_SEQUENCE,
148: DEFAULT_STROKE_SEQUENCE,
149: DEFAULT_OUTLINE_STROKE_SEQUENCE, DEFAULT_SHAPE_SEQUENCE);
150:
151: }
152:
153: /**
154: * Creates a new supplier.
155: *
156: * @param paintSequence the fill paint sequence.
157: * @param outlinePaintSequence the outline paint sequence.
158: * @param strokeSequence the stroke sequence.
159: * @param outlineStrokeSequence the outline stroke sequence.
160: * @param shapeSequence the shape sequence.
161: */
162: public DefaultDrawingSupplier(Paint[] paintSequence,
163: Paint[] outlinePaintSequence, Stroke[] strokeSequence,
164: Stroke[] outlineStrokeSequence, Shape[] shapeSequence) {
165:
166: this .paintSequence = paintSequence;
167: this .fillPaintSequence = DEFAULT_FILL_PAINT_SEQUENCE;
168: this .outlinePaintSequence = outlinePaintSequence;
169: this .strokeSequence = strokeSequence;
170: this .outlineStrokeSequence = outlineStrokeSequence;
171: this .shapeSequence = shapeSequence;
172:
173: }
174:
175: /**
176: * Creates a new supplier.
177: *
178: * @param paintSequence the paint sequence.
179: * @param fillPaintSequence the fill paint sequence.
180: * @param outlinePaintSequence the outline paint sequence.
181: * @param strokeSequence the stroke sequence.
182: * @param outlineStrokeSequence the outline stroke sequence.
183: * @param shapeSequence the shape sequence.
184: *
185: * @since 1.0.6
186: */
187: public DefaultDrawingSupplier(Paint[] paintSequence,
188: Paint[] fillPaintSequence, Paint[] outlinePaintSequence,
189: Stroke[] strokeSequence, Stroke[] outlineStrokeSequence,
190: Shape[] shapeSequence) {
191:
192: this .paintSequence = paintSequence;
193: this .fillPaintSequence = fillPaintSequence;
194: this .outlinePaintSequence = outlinePaintSequence;
195: this .strokeSequence = strokeSequence;
196: this .outlineStrokeSequence = outlineStrokeSequence;
197: this .shapeSequence = shapeSequence;
198: }
199:
200: /**
201: * Returns the next paint in the sequence.
202: *
203: * @return The paint.
204: */
205: public Paint getNextPaint() {
206: Paint result = this .paintSequence[this .paintIndex
207: % this .paintSequence.length];
208: this .paintIndex++;
209: return result;
210: }
211:
212: /**
213: * Returns the next outline paint in the sequence.
214: *
215: * @return The paint.
216: */
217: public Paint getNextOutlinePaint() {
218: Paint result = this .outlinePaintSequence[this .outlinePaintIndex
219: % this .outlinePaintSequence.length];
220: this .outlinePaintIndex++;
221: return result;
222: }
223:
224: /**
225: * Returns the next fill paint in the sequence.
226: *
227: * @return The paint.
228: *
229: * @since 1.0.6
230: */
231: public Paint getNextFillPaint() {
232: Paint result = this .fillPaintSequence[this .fillPaintIndex
233: % this .fillPaintSequence.length];
234: this .fillPaintIndex++;
235: return result;
236: }
237:
238: /**
239: * Returns the next stroke in the sequence.
240: *
241: * @return The stroke.
242: */
243: public Stroke getNextStroke() {
244: Stroke result = this .strokeSequence[this .strokeIndex
245: % this .strokeSequence.length];
246: this .strokeIndex++;
247: return result;
248: }
249:
250: /**
251: * Returns the next outline stroke in the sequence.
252: *
253: * @return The stroke.
254: */
255: public Stroke getNextOutlineStroke() {
256: Stroke result = this .outlineStrokeSequence[this .outlineStrokeIndex
257: % this .outlineStrokeSequence.length];
258: this .outlineStrokeIndex++;
259: return result;
260: }
261:
262: /**
263: * Returns the next shape in the sequence.
264: *
265: * @return The shape.
266: */
267: public Shape getNextShape() {
268: Shape result = this .shapeSequence[this .shapeIndex
269: % this .shapeSequence.length];
270: this .shapeIndex++;
271: return result;
272: }
273:
274: /**
275: * Creates an array of standard shapes to display for the items in series
276: * on charts.
277: *
278: * @return The array of shapes.
279: */
280: public static Shape[] createStandardSeriesShapes() {
281:
282: Shape[] result = new Shape[10];
283:
284: double size = 6.0;
285: double delta = size / 2.0;
286: int[] xpoints = null;
287: int[] ypoints = null;
288:
289: // square
290: result[0] = new Rectangle2D.Double(-delta, -delta, size, size);
291: // circle
292: result[1] = new Ellipse2D.Double(-delta, -delta, size, size);
293:
294: // up-pointing triangle
295: xpoints = intArray(0.0, delta, -delta);
296: ypoints = intArray(-delta, delta, delta);
297: result[2] = new Polygon(xpoints, ypoints, 3);
298:
299: // diamond
300: xpoints = intArray(0.0, delta, 0.0, -delta);
301: ypoints = intArray(-delta, 0.0, delta, 0.0);
302: result[3] = new Polygon(xpoints, ypoints, 4);
303:
304: // horizontal rectangle
305: result[4] = new Rectangle2D.Double(-delta, -delta / 2, size,
306: size / 2);
307:
308: // down-pointing triangle
309: xpoints = intArray(-delta, +delta, 0.0);
310: ypoints = intArray(-delta, -delta, delta);
311: result[5] = new Polygon(xpoints, ypoints, 3);
312:
313: // horizontal ellipse
314: result[6] = new Ellipse2D.Double(-delta, -delta / 2, size,
315: size / 2);
316:
317: // right-pointing triangle
318: xpoints = intArray(-delta, delta, -delta);
319: ypoints = intArray(-delta, 0.0, delta);
320: result[7] = new Polygon(xpoints, ypoints, 3);
321:
322: // vertical rectangle
323: result[8] = new Rectangle2D.Double(-delta / 2, -delta,
324: size / 2, size);
325:
326: // left-pointing triangle
327: xpoints = intArray(-delta, delta, delta);
328: ypoints = intArray(0.0, -delta, +delta);
329: result[9] = new Polygon(xpoints, ypoints, 3);
330:
331: return result;
332:
333: }
334:
335: /**
336: * Tests this object for equality with another object.
337: *
338: * @param obj the object (<code>null</code> permitted).
339: *
340: * @return A boolean.
341: */
342: public boolean equals(Object obj) {
343:
344: if (obj == this ) {
345: return true;
346: }
347:
348: if (!(obj instanceof DefaultDrawingSupplier)) {
349: return false;
350: }
351:
352: DefaultDrawingSupplier that = (DefaultDrawingSupplier) obj;
353:
354: if (!Arrays.equals(this .paintSequence, that.paintSequence)) {
355: return false;
356: }
357: if (this .paintIndex != that.paintIndex) {
358: return false;
359: }
360: if (!Arrays.equals(this .outlinePaintSequence,
361: that.outlinePaintSequence)) {
362: return false;
363: }
364: if (this .outlinePaintIndex != that.outlinePaintIndex) {
365: return false;
366: }
367: if (!Arrays.equals(this .strokeSequence, that.strokeSequence)) {
368: return false;
369: }
370: if (this .strokeIndex != that.strokeIndex) {
371: return false;
372: }
373: if (!Arrays.equals(this .outlineStrokeSequence,
374: that.outlineStrokeSequence)) {
375: return false;
376: }
377: if (this .outlineStrokeIndex != that.outlineStrokeIndex) {
378: return false;
379: }
380: if (!equalShapes(this .shapeSequence, that.shapeSequence)) {
381: return false;
382: }
383: if (this .shapeIndex != that.shapeIndex) {
384: return false;
385: }
386: return true;
387:
388: }
389:
390: /**
391: * A utility method for testing the equality of two arrays of shapes.
392: *
393: * @param s1 the first array (<code>null</code> permitted).
394: * @param s2 the second array (<code>null</code> permitted).
395: *
396: * @return A boolean.
397: */
398: private boolean equalShapes(Shape[] s1, Shape[] s2) {
399: if (s1 == null) {
400: return s2 == null;
401: }
402: if (s2 == null) {
403: return false;
404: }
405: if (s1.length != s2.length) {
406: return false;
407: }
408: for (int i = 0; i < s1.length; i++) {
409: if (!ShapeUtilities.equal(s1[i], s2[i])) {
410: return false;
411: }
412: }
413: return true;
414: }
415:
416: /**
417: * Handles serialization.
418: *
419: * @param stream the output stream.
420: *
421: * @throws IOException if there is an I/O problem.
422: */
423: private void writeObject(ObjectOutputStream stream)
424: throws IOException {
425: stream.defaultWriteObject();
426:
427: int paintCount = this .paintSequence.length;
428: stream.writeInt(paintCount);
429: for (int i = 0; i < paintCount; i++) {
430: SerialUtilities.writePaint(this .paintSequence[i], stream);
431: }
432:
433: int outlinePaintCount = this .outlinePaintSequence.length;
434: stream.writeInt(outlinePaintCount);
435: for (int i = 0; i < outlinePaintCount; i++) {
436: SerialUtilities.writePaint(this .outlinePaintSequence[i],
437: stream);
438: }
439:
440: int strokeCount = this .strokeSequence.length;
441: stream.writeInt(strokeCount);
442: for (int i = 0; i < strokeCount; i++) {
443: SerialUtilities.writeStroke(this .strokeSequence[i], stream);
444: }
445:
446: int outlineStrokeCount = this .outlineStrokeSequence.length;
447: stream.writeInt(outlineStrokeCount);
448: for (int i = 0; i < outlineStrokeCount; i++) {
449: SerialUtilities.writeStroke(this .outlineStrokeSequence[i],
450: stream);
451: }
452:
453: int shapeCount = this .shapeSequence.length;
454: stream.writeInt(shapeCount);
455: for (int i = 0; i < shapeCount; i++) {
456: SerialUtilities.writeShape(this .shapeSequence[i], stream);
457: }
458:
459: }
460:
461: /**
462: * Restores a serialized object.
463: *
464: * @param stream the input stream.
465: *
466: * @throws IOException if there is an I/O problem.
467: * @throws ClassNotFoundException if there is a problem loading a class.
468: */
469: private void readObject(ObjectInputStream stream)
470: throws IOException, ClassNotFoundException {
471: stream.defaultReadObject();
472:
473: int paintCount = stream.readInt();
474: this .paintSequence = new Paint[paintCount];
475: for (int i = 0; i < paintCount; i++) {
476: this .paintSequence[i] = SerialUtilities.readPaint(stream);
477: }
478:
479: int outlinePaintCount = stream.readInt();
480: this .outlinePaintSequence = new Paint[outlinePaintCount];
481: for (int i = 0; i < outlinePaintCount; i++) {
482: this .outlinePaintSequence[i] = SerialUtilities
483: .readPaint(stream);
484: }
485:
486: int strokeCount = stream.readInt();
487: this .strokeSequence = new Stroke[strokeCount];
488: for (int i = 0; i < strokeCount; i++) {
489: this .strokeSequence[i] = SerialUtilities.readStroke(stream);
490: }
491:
492: int outlineStrokeCount = stream.readInt();
493: this .outlineStrokeSequence = new Stroke[outlineStrokeCount];
494: for (int i = 0; i < outlineStrokeCount; i++) {
495: this .outlineStrokeSequence[i] = SerialUtilities
496: .readStroke(stream);
497: }
498:
499: int shapeCount = stream.readInt();
500: this .shapeSequence = new Shape[shapeCount];
501: for (int i = 0; i < shapeCount; i++) {
502: this .shapeSequence[i] = SerialUtilities.readShape(stream);
503: }
504:
505: }
506:
507: /**
508: * Helper method to avoid lots of explicit casts in getShape(). Returns
509: * an array containing the provided doubles cast to ints.
510: *
511: * @param a x
512: * @param b y
513: * @param c z
514: *
515: * @return int[3] with converted params.
516: */
517: private static int[] intArray(double a, double b, double c) {
518: return new int[] { (int) a, (int) b, (int) c };
519: }
520:
521: /**
522: * Helper method to avoid lots of explicit casts in getShape(). Returns
523: * an array containing the provided doubles cast to ints.
524: *
525: * @param a x
526: * @param b y
527: * @param c z
528: * @param d t
529: *
530: * @return int[4] with converted params.
531: */
532: private static int[] intArray(double a, double b, double c, double d) {
533: return new int[] { (int) a, (int) b, (int) c, (int) d };
534: }
535:
536: /**
537: * Returns a clone.
538: *
539: * @return A clone.
540: *
541: * @throws CloneNotSupportedException if a component of the supplier does
542: * not support cloning.
543: */
544: public Object clone() throws CloneNotSupportedException {
545: DefaultDrawingSupplier clone = (DefaultDrawingSupplier) super
546: .clone();
547: return clone;
548: }
549: }
|