KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > plot > PolarPlot


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * --------------
28  * PolarPlot.java
29  * --------------
30  * (C) Copyright 2004-2006, by Solution Engineering, Inc. and Contributors.
31  *
32  * Original Author: Daniel Bridenbecker, Solution Engineering, Inc.;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: PolarPlot.java,v 1.13.2.5 2006/09/07 16:05:51 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 19-Jan-2004 : Version 1, contributed by DB with minor changes by DG (DG);
40  * 07-Apr-2004 : Changed text bounds calculation (DG);
41  * 05-May-2005 : Updated draw() method parameters (DG);
42  * 09-Jun-2005 : Fixed getDataRange() and equals() methods (DG);
43  * 25-Oct-2005 : Implemented Zoomable (DG);
44  *
45  */

46
47 package org.jfree.chart.plot;
48
49 import java.awt.AlphaComposite JavaDoc;
50 import java.awt.BasicStroke JavaDoc;
51 import java.awt.Color JavaDoc;
52 import java.awt.Composite JavaDoc;
53 import java.awt.Font JavaDoc;
54 import java.awt.FontMetrics JavaDoc;
55 import java.awt.Graphics2D JavaDoc;
56 import java.awt.Paint JavaDoc;
57 import java.awt.Point JavaDoc;
58 import java.awt.Shape JavaDoc;
59 import java.awt.Stroke JavaDoc;
60 import java.awt.geom.Point2D JavaDoc;
61 import java.awt.geom.Rectangle2D JavaDoc;
62 import java.io.IOException JavaDoc;
63 import java.io.ObjectInputStream JavaDoc;
64 import java.io.ObjectOutputStream JavaDoc;
65 import java.io.Serializable JavaDoc;
66 import java.util.ArrayList JavaDoc;
67 import java.util.Iterator JavaDoc;
68 import java.util.List JavaDoc;
69 import java.util.ResourceBundle JavaDoc;
70
71 import org.jfree.chart.LegendItem;
72 import org.jfree.chart.LegendItemCollection;
73 import org.jfree.chart.axis.AxisState;
74 import org.jfree.chart.axis.NumberTick;
75 import org.jfree.chart.axis.ValueAxis;
76 import org.jfree.chart.event.PlotChangeEvent;
77 import org.jfree.chart.event.RendererChangeEvent;
78 import org.jfree.chart.event.RendererChangeListener;
79 import org.jfree.chart.renderer.PolarItemRenderer;
80 import org.jfree.data.Range;
81 import org.jfree.data.general.DatasetChangeEvent;
82 import org.jfree.data.general.DatasetUtilities;
83 import org.jfree.data.xy.XYDataset;
84 import org.jfree.io.SerialUtilities;
85 import org.jfree.text.TextUtilities;
86 import org.jfree.ui.RectangleEdge;
87 import org.jfree.ui.RectangleInsets;
88 import org.jfree.ui.TextAnchor;
89 import org.jfree.util.ObjectUtilities;
90 import org.jfree.util.PaintUtilities;
91
92
93 /**
94  * Plots data that is in (theta, radius) pairs where
95  * theta equal to zero is due north and and increases clockwise.
96  *
97  * @author Daniel Bridenbecker, Solution Engineering, Inc.
98  */

99 public class PolarPlot extends Plot implements ValueAxisPlot,
100                                                Zoomable,
101                                                RendererChangeListener,
102                                                Cloneable JavaDoc,
103                                                Serializable JavaDoc {
104    
105     /** For serialization. */
106     private static final long serialVersionUID = 3794383185924179525L;
107     
108     /** The default margin. */
109     private static final int MARGIN = 20;
110    
111     /** The annotation margin. */
112     private static final double ANNOTATION_MARGIN = 7.0;
113    
114     /** The default grid line stroke. */
115     public static final Stroke JavaDoc DEFAULT_GRIDLINE_STROKE = new BasicStroke JavaDoc(
116             0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL,
117             0.0f, new float[]{2.0f, 2.0f}, 0.0f);
118    
119     /** The default grid line paint. */
120     public static final Paint JavaDoc DEFAULT_GRIDLINE_PAINT = Color.gray;
121    
122     /** The resourceBundle for the localization. */
123     protected static ResourceBundle JavaDoc localizationResources
124         = ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
125    
126     // ------------------------
127
// --- Member Variables ---
128
// ------------------------
129
/** The angles that are marked with gridlines. */
130     private List JavaDoc angleTicks;
131     
132     /** The axis (used for the y-values). */
133     private ValueAxis axis;
134     
135     /** The dataset. */
136     private XYDataset dataset;
137    
138     /**
139      * Object responsible for drawing the visual representation of each point
140      * on the plot.
141      */

142     private PolarItemRenderer renderer;
143    
144     /** A flag that controls whether or not the angle labels are visible. */
145     private boolean angleLabelsVisible = true;
146     
147     /** The font used to display the angle labels - never null. */
148     private Font JavaDoc angleLabelFont = new Font JavaDoc("SansSerif", Font.PLAIN, 12);
149     
150     /** The paint used to display the angle labels. */
151     private Paint JavaDoc angleLabelPaint = Color.black;
152     
153     /** A flag that controls whether the angular grid-lines are visible. */
154     private boolean angleGridlinesVisible;
155    
156     /** The stroke used to draw the angular grid-lines. */
157     private transient Stroke JavaDoc angleGridlineStroke;
158    
159     /** The paint used to draw the angular grid-lines. */
160     private transient Paint JavaDoc angleGridlinePaint;
161    
162     /** A flag that controls whether the radius grid-lines are visible. */
163     private boolean radiusGridlinesVisible;
164    
165     /** The stroke used to draw the radius grid-lines. */
166     private transient Stroke JavaDoc radiusGridlineStroke;
167    
168     /** The paint used to draw the radius grid-lines. */
169     private transient Paint JavaDoc radiusGridlinePaint;
170    
171     /** The annotations for the plot. */
172     private List JavaDoc cornerTextItems = new ArrayList JavaDoc();
173    
174     // --------------------
175
// --- Constructors ---
176
// --------------------
177
/**
178      * Default constructor.
179      */

180     public PolarPlot() {
181         this(null, null, null);
182     }
183    
184    /**
185      * Creates a new plot.
186      *
187      * @param dataset the dataset (<code>null</code> permitted).
188      * @param radiusAxis the radius axis (<code>null</code> permitted).
189      * @param renderer the renderer (<code>null</code> permitted).
190      */

191     public PolarPlot(XYDataset dataset,
192                      ValueAxis radiusAxis,
193                      PolarItemRenderer renderer) {
194       
195         super();
196             
197         this.dataset = dataset;
198         if (this.dataset != null) {
199             this.dataset.addChangeListener(this);
200         }
201       
202         this.angleTicks = new java.util.ArrayList JavaDoc();
203         this.angleTicks.add(new NumberTick(new Double JavaDoc(0.0), "0",
204                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
205         this.angleTicks.add(new NumberTick(new Double JavaDoc(45.0), "45",
206                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
207         this.angleTicks.add(new NumberTick(new Double JavaDoc(90.0), "90",
208                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
209         this.angleTicks.add(new NumberTick(new Double JavaDoc(135.0), "135",
210                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
211         this.angleTicks.add(new NumberTick(new Double JavaDoc(180.0), "180",
212                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
213         this.angleTicks.add(new NumberTick(new Double JavaDoc(225.0), "225",
214                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
215         this.angleTicks.add(new NumberTick(new Double JavaDoc(270.0), "270",
216                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
217         this.angleTicks.add(new NumberTick(new Double JavaDoc(315.0), "315",
218                 TextAnchor.CENTER, TextAnchor.CENTER, 0.0));
219         
220         this.axis = radiusAxis;
221         if (this.axis != null) {
222             this.axis.setPlot(this);
223             this.axis.addChangeListener(this);
224         }
225       
226         this.renderer = renderer;
227         if (this.renderer != null) {
228             this.renderer.setPlot(this);
229             this.renderer.addChangeListener(this);
230         }
231       
232         this.angleGridlinesVisible = true;
233         this.angleGridlineStroke = DEFAULT_GRIDLINE_STROKE;
234         this.angleGridlinePaint = DEFAULT_GRIDLINE_PAINT;
235       
236         this.radiusGridlinesVisible = true;
237         this.radiusGridlineStroke = DEFAULT_GRIDLINE_STROKE;
238         this.radiusGridlinePaint = DEFAULT_GRIDLINE_PAINT;
239     }
240    
241     /**
242      * Add text to be displayed in the lower right hand corner.
243      *
244      * @param text the text to display (<code>null</code> not permitted).
245      */

246     public void addCornerTextItem(String JavaDoc text) {
247         if (text == null) {
248             throw new IllegalArgumentException JavaDoc("Null 'text' argument.");
249         }
250         this.cornerTextItems.add(text);
251         this.notifyListeners(new PlotChangeEvent(this));
252     }
253    
254     /**
255      * Remove the given text from the list of corner text items.
256      *
257      * @param text the text to remove (<code>null</code> ignored).
258      */

259     public void removeCornerTextItem(String JavaDoc text) {
260         boolean removed = this.cornerTextItems.remove(text);
261         if (removed) {
262             this.notifyListeners(new PlotChangeEvent(this));
263         }
264     }
265    
266     /**
267      * Clear the list of corner text items.
268      */

269     public void clearCornerTextItems() {
270         if (this.cornerTextItems.size() > 0) {
271             this.cornerTextItems.clear();
272             this.notifyListeners(new PlotChangeEvent(this));
273         }
274     }
275    
276     /**
277      * Returns the plot type as a string.
278      *
279      * @return A short string describing the type of plot.
280      */

281     public String JavaDoc getPlotType() {
282        return PolarPlot.localizationResources.getString("Polar_Plot");
283     }
284     
285     /**
286      * Returns the axis for the plot.
287      *
288      * @return The radius axis.
289      */

290     public ValueAxis getAxis() {
291         return this.axis;
292     }
293    
294     /**
295      * Sets the axis for the plot and sends a {@link PlotChangeEvent} to all
296      * registered listeners.
297      *
298      * @param axis the new axis (<code>null</code> permitted).
299      */

300     public void setAxis(ValueAxis axis) {
301         if (axis != null) {
302             axis.setPlot(this);
303         }
304        
305         // plot is likely registered as a listener with the existing axis...
306
if (this.axis != null) {
307             this.axis.removeChangeListener(this);
308         }
309        
310         this.axis = axis;
311         if (this.axis != null) {
312             this.axis.configure();
313             this.axis.addChangeListener(this);
314         }
315         notifyListeners(new PlotChangeEvent(this));
316     }
317    
318     /**
319      * Returns the primary dataset for the plot.
320      *
321      * @return The primary dataset (possibly <code>null</code>).
322      */

323     public XYDataset getDataset() {
324         return this.dataset;
325     }
326     
327     /**
328      * Sets the dataset for the plot, replacing the existing dataset if there
329      * is one.
330      *
331      * @param dataset the dataset (<code>null</code> permitted).
332      */

333     public void setDataset(XYDataset dataset) {
334         // if there is an existing dataset, remove the plot from the list of
335
// change listeners...
336
XYDataset existing = this.dataset;
337         if (existing != null) {
338             existing.removeChangeListener(this);
339         }
340        
341         // set the new m_Dataset, and register the chart as a change listener...
342
this.dataset = dataset;
343         if (this.dataset != null) {
344             setDatasetGroup(this.dataset.getGroup());
345             this.dataset.addChangeListener(this);
346         }
347        
348         // send a m_Dataset change event to self...
349
DatasetChangeEvent event = new DatasetChangeEvent(this, this.dataset);
350         datasetChanged(event);
351     }
352    
353     /**
354      * Returns the item renderer.
355      *
356      * @return The renderer (possibly <code>null</code>).
357      */

358     public PolarItemRenderer getRenderer() {
359         return this.renderer;
360     }
361    
362     /**
363      * Sets the item renderer, and notifies all listeners of a change to the
364      * plot.
365      * <P>
366      * If the renderer is set to <code>null</code>, no chart will be drawn.
367      *
368      * @param renderer the new renderer (<code>null</code> permitted).
369      */

370     public void setRenderer(PolarItemRenderer renderer) {
371         if (this.renderer != null) {
372             this.renderer.removeChangeListener(this);
373         }
374        
375         this.renderer = renderer;
376         if (this.renderer != null) {
377             this.renderer.setPlot(this);
378         }
379        
380         notifyListeners(new PlotChangeEvent(this));
381     }
382    
383     /**
384      * Returns a flag that controls whether or not the angle labels are visible.
385      *
386      * @return A boolean.
387      */

388     public boolean isAngleLabelsVisible() {
389         return this.angleLabelsVisible;
390     }
391     
392     /**
393      * Sets the flag that controls whether or not the angle labels are visible,
394      * and sends a {@link PlotChangeEvent} to all registered listeners.
395      *
396      * @param visible the flag.
397      */

398     public void setAngleLabelsVisible(boolean visible) {
399         if (this.angleLabelsVisible != visible) {
400             this.angleLabelsVisible = visible;
401             notifyListeners(new PlotChangeEvent(this));
402         }
403     }
404     
405     /**
406      * Returns the font used to display the angle labels.
407      *
408      * @return A font (never <code>null</code>).
409      */

410     public Font JavaDoc getAngleLabelFont() {
411         return this.angleLabelFont;
412     }
413     
414     /**
415      * Sets the font used to display the angle labels and sends a
416      * {@link PlotChangeEvent} to all registered listeners.
417      *
418      * @param font the font (<code>null</code> not permitted).
419      */

420     public void setAngleLabelFont(Font JavaDoc font) {
421         if (font == null) {
422             throw new IllegalArgumentException JavaDoc("Null 'font' argument.");
423         }
424         this.angleLabelFont = font;
425         notifyListeners(new PlotChangeEvent(this));
426     }
427     
428     /**
429      * Returns the paint used to display the angle labels.
430      *
431      * @return A paint.
432      */

433     public Paint JavaDoc getAngleLabelPaint() {
434         return this.angleLabelPaint;
435     }
436     
437     /**
438      * Sets the paint used to display the angle labels and sends a
439      * {@link PlotChangeEvent} to all registered listeners.
440      *
441      * @param paint the paint.
442      */

443     public void setAngleLabelPaint(Paint JavaDoc paint) {
444         this.angleLabelPaint = paint;
445         notifyListeners(new PlotChangeEvent(this));
446     }
447     
448     /**
449      * Returns <code>true</code> if the angular gridlines are visible, and
450      * <code>false<code> otherwise.
451      *
452      * @return <code>true</code> or <code>false</code>.
453      */

454     public boolean isAngleGridlinesVisible() {
455         return this.angleGridlinesVisible;
456     }
457     
458     /**
459      * Sets the flag that controls whether or not the angular grid-lines are
460      * visible.
461      * <p>
462      * If the flag value is changed, a {@link PlotChangeEvent} is sent to all
463      * registered listeners.
464      *
465      * @param visible the new value of the flag.
466      */

467     public void setAngleGridlinesVisible(boolean visible) {
468         if (this.angleGridlinesVisible != visible) {
469             this.angleGridlinesVisible = visible;
470             notifyListeners(new PlotChangeEvent(this));
471         }
472     }
473    
474     /**
475      * Returns the stroke for the grid-lines (if any) plotted against the
476      * angular axis.
477      *
478      * @return The stroke.
479      */

480     public Stroke JavaDoc getAngleGridlineStroke() {
481         return this.angleGridlineStroke;
482     }
483     
484     /**
485      * Sets the stroke for the grid lines plotted against the angular axis.
486      * <p>
487      * If you set this to <code>null</code>, no grid lines will be drawn.
488      *
489      * @param stroke the stroke (<code>null</code> permitted).
490      */

491     public void setAngleGridlineStroke(Stroke JavaDoc stroke) {
492         this.angleGridlineStroke = stroke;
493         notifyListeners(new PlotChangeEvent(this));
494     }
495     
496     /**
497      * Returns the paint for the grid lines (if any) plotted against the
498      * angular axis.
499      *
500      * @return The paint.
501      */

502     public Paint JavaDoc getAngleGridlinePaint() {
503         return this.angleGridlinePaint;
504     }
505    
506     /**
507      * Sets the paint for the grid lines plotted against the angular axis.
508      * <p>
509      * If you set this to <code>null</code>, no grid lines will be drawn.
510      *
511      * @param paint the paint (<code>null</code> permitted).
512      */

513     public void setAngleGridlinePaint(Paint JavaDoc paint) {
514         this.angleGridlinePaint = paint;
515         notifyListeners(new PlotChangeEvent(this));
516     }
517     
518     /**
519      * Returns <code>true</code> if the radius axis grid is visible, and
520      * <code>false<code> otherwise.
521      *
522      * @return <code>true</code> or <code>false</code>.
523      */

524     public boolean isRadiusGridlinesVisible() {
525         return this.radiusGridlinesVisible;
526     }
527     
528     /**
529      * Sets the flag that controls whether or not the radius axis grid lines
530      * are visible.
531      * <p>
532      * If the flag value is changed, a {@link PlotChangeEvent} is sent to all
533      * registered listeners.
534      *
535      * @param visible the new value of the flag.
536      */

537     public void setRadiusGridlinesVisible(boolean visible) {
538         if (this.radiusGridlinesVisible != visible) {
539             this.radiusGridlinesVisible = visible;
540             notifyListeners(new PlotChangeEvent(this));
541         }
542     }
543    
544     /**
545      * Returns the stroke for the grid lines (if any) plotted against the
546      * radius axis.
547      *
548      * @return The stroke.
549      */

550     public Stroke JavaDoc getRadiusGridlineStroke() {
551         return this.radiusGridlineStroke;
552     }
553     
554     /**
555      * Sets the stroke for the grid lines plotted against the radius axis.
556      * <p>
557      * If you set this to <code>null</code>, no grid lines will be drawn.
558      *
559      * @param stroke the stroke (<code>null</code> permitted).
560      */

561     public void setRadiusGridlineStroke(Stroke JavaDoc stroke) {
562         this.radiusGridlineStroke = stroke;
563         notifyListeners(new PlotChangeEvent(this));
564     }
565     
566     /**
567      * Returns the paint for the grid lines (if any) plotted against the radius
568      * axis.
569      *
570      * @return The paint.
571      */

572     public Paint JavaDoc getRadiusGridlinePaint() {
573         return this.radiusGridlinePaint;
574     }
575     
576     /**
577      * Sets the paint for the grid lines plotted against the radius axis.
578      * <p>
579      * If you set this to <code>null</code>, no grid lines will be drawn.
580      *
581      * @param paint the paint (<code>null</code> permitted).
582      */

583     public void setRadiusGridlinePaint(Paint JavaDoc paint) {
584         this.radiusGridlinePaint = paint;
585         notifyListeners(new PlotChangeEvent(this));
586     }
587     
588     /**
589      * Draws the plot on a Java 2D graphics device (such as the screen or a
590      * printer).
591      * <P>
592      * This plot relies on an
593      * {@link org.jfree.chart.renderer.DefaultPolarItemRenderer} to draw each
594      * item in the plot. This allows the visual representation of the data to
595      * be changed easily.
596      * <P>
597      * The optional info argument collects information about the rendering of
598      * the plot (dimensions, tooltip information etc). Just pass in
599      * <code>null</code> if you do not need this information.
600      *
601      * @param g2 the graphics device.
602      * @param area the area within which the plot (including axes and
603      * labels) should be drawn.
604      * @param anchor the anchor point (<code>null</code> permitted).
605      * @param parentState ignored.
606      * @param info collects chart drawing information (<code>null</code>
607      * permitted).
608      */

609     public void draw(Graphics2D JavaDoc g2,
610                      Rectangle2D JavaDoc area,
611                      Point2D JavaDoc anchor,
612                      PlotState parentState,
613                      PlotRenderingInfo info) {
614        
615         // if the plot area is too small, just return...
616
boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW);
617         boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW);
618         if (b1 || b2) {
619             return;
620         }
621        
622         // record the plot area...
623
if (info != null) {
624             info.setPlotArea(area);
625         }
626        
627         // adjust the drawing area for the plot insets (if any)...
628
RectangleInsets insets = getInsets();
629         insets.trim(area);
630       
631         Rectangle2D JavaDoc dataArea = area;
632         if (info != null) {
633             info.setDataArea(dataArea);
634         }
635        
636         // draw the plot background and axes...
637
drawBackground(g2, dataArea);
638         double h = Math.min(dataArea.getWidth() / 2.0,
639                 dataArea.getHeight() / 2.0) - MARGIN;
640         Rectangle2D JavaDoc quadrant = new Rectangle2D.Double JavaDoc(dataArea.getCenterX(),
641                 dataArea.getCenterY(), h, h);
642         AxisState state = drawAxis(g2, area, quadrant);
643         if (this.renderer != null) {
644             Shape JavaDoc originalClip = g2.getClip();
645             Composite JavaDoc originalComposite = g2.getComposite();
646           
647             g2.clip(dataArea);
648             g2.setComposite(AlphaComposite.getInstance(
649                     AlphaComposite.SRC_OVER, getForegroundAlpha()));
650           
651             drawGridlines(g2, dataArea, this.angleTicks, state.getTicks());
652           
653             // draw...
654
render(g2, dataArea, info);
655           
656             g2.setClip(originalClip);
657             g2.setComposite(originalComposite);
658         }
659         drawOutline(g2, dataArea);
660         drawCornerTextItems(g2, dataArea);
661     }
662    
663     /**
664      * Draws the corner text items.
665      *
666      * @param g2 the drawing surface.
667      * @param area the area.
668      */

669     protected void drawCornerTextItems(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area) {
670         if (this.cornerTextItems.isEmpty()) {
671             return;
672         }
673        
674         g2.setColor(Color.black);
675         double width = 0.0;
676         double height = 0.0;
677         for (Iterator JavaDoc it = this.cornerTextItems.iterator(); it.hasNext();) {
678             String JavaDoc msg = (String JavaDoc) it.next();
679             FontMetrics JavaDoc fm = g2.getFontMetrics();
680             Rectangle2D JavaDoc bounds = TextUtilities.getTextBounds(msg, g2, fm);
681             width = Math.max(width, bounds.getWidth());
682             height += bounds.getHeight();
683         }
684         
685         double xadj = ANNOTATION_MARGIN * 2.0;
686         double yadj = ANNOTATION_MARGIN;
687         width += xadj;
688         height += yadj;
689        
690         double x = area.getMaxX() - width;
691         double y = area.getMaxY() - height;
692         g2.drawRect((int) x, (int) y, (int) width, (int) height);
693         x += ANNOTATION_MARGIN;
694         for (Iterator JavaDoc it = this.cornerTextItems.iterator(); it.hasNext();) {
695             String JavaDoc msg = (String JavaDoc) it.next();
696             Rectangle2D JavaDoc bounds = TextUtilities.getTextBounds(msg, g2,
697                     g2.getFontMetrics());
698             y += bounds.getHeight();
699             g2.drawString(msg, (int) x, (int) y);
700         }
701     }
702    
703     /**
704      * A utility method for drawing the axes.
705      *
706      * @param g2 the graphics device.
707      * @param plotArea the plot area.
708      * @param dataArea the data area.
709      *
710      * @return A map containing the axis states.
711      */

712     protected AxisState drawAxis(Graphics2D JavaDoc g2, Rectangle2D JavaDoc plotArea,
713                                  Rectangle2D JavaDoc dataArea) {
714         return this.axis.draw(g2, dataArea.getMinY(), plotArea, dataArea,
715                 RectangleEdge.TOP, null);
716     }
717    
718     /**
719      * Draws a representation of the data within the dataArea region, using the
720      * current m_Renderer.
721      *
722      * @param g2 the graphics device.
723      * @param dataArea the region in which the data is to be drawn.
724      * @param info an optional object for collection dimension
725      * information (<code>null</code> permitted).
726      */

727     protected void render(Graphics2D JavaDoc g2,
728                        Rectangle2D JavaDoc dataArea,
729                        PlotRenderingInfo info) {
730       
731         // now get the data and plot it (the visual representation will depend
732
// on the m_Renderer that has been set)...
733
if (!DatasetUtilities.isEmptyOrNull(this.dataset)) {
734             int seriesCount = this.dataset.getSeriesCount();
735             for (int series = 0; series < seriesCount; series++) {
736                 this.renderer.drawSeries(g2, dataArea, info, this,
737                         this.dataset, series);
738             }
739         }
740         else {
741             drawNoDataMessage(g2, dataArea);
742         }
743     }
744    
745     /**
746      * Draws the gridlines for the plot, if they are visible.
747      *
748      * @param g2 the graphics device.
749      * @param dataArea the data area.
750      * @param angularTicks the ticks for the angular axis.
751      * @param radialTicks the ticks for the radial axis.
752      */

753     protected void drawGridlines(Graphics2D JavaDoc g2, Rectangle2D JavaDoc dataArea,
754                                  List JavaDoc angularTicks, List JavaDoc radialTicks) {
755
756         // no renderer, no gridlines...
757
if (this.renderer == null) {
758             return;
759         }
760        
761         // draw the domain grid lines, if any...
762
if (isAngleGridlinesVisible()) {
763             Stroke JavaDoc gridStroke = getAngleGridlineStroke();
764             Paint JavaDoc gridPaint = getAngleGridlinePaint();
765             if ((gridStroke != null) && (gridPaint != null)) {
766                 this.renderer.drawAngularGridLines(g2, this, angularTicks,
767                         dataArea);
768             }
769         }
770        
771         // draw the radius grid lines, if any...
772
if (isRadiusGridlinesVisible()) {
773             Stroke JavaDoc gridStroke = getRadiusGridlineStroke();
774             Paint JavaDoc gridPaint = getRadiusGridlinePaint();
775             if ((gridStroke != null) && (gridPaint != null)) {
776                 this.renderer.drawRadialGridLines(g2, this, this.axis,
777                         radialTicks, dataArea);
778             }
779         }
780     }
781    
782     /**
783      * Zooms the axis ranges by the specified percentage about the anchor point.
784      *
785      * @param percent the amount of the zoom.
786      */

787     public void zoom(double percent) {
788         if (percent > 0.0) {
789             double radius = getMaxRadius();
790             double scaledRadius = radius * percent;
791             this.axis.setUpperBound(scaledRadius);
792             getAxis().setAutoRange(false);
793         }
794         else {
795             getAxis().setAutoRange(true);
796         }
797     }
798    
799     /**
800      * Returns the range for the specified axis.
801      *
802      * @param axis the axis.
803      *
804      * @return The range.
805      */

806     public Range getDataRange(ValueAxis axis) {
807         Range result = null;
808         if (this.dataset != null) {
809             result = Range.combine(result,
810                     DatasetUtilities.findRangeBounds(this.dataset));
811         }
812         return result;
813     }
814    
815     /**
816      * Receives notification of a change to the plot's m_Dataset.
817      * <P>
818      * The axis ranges are updated if necessary.
819      *
820      * @param event information about the event (not used here).
821      */

822     public void datasetChanged(DatasetChangeEvent event) {
823
824         if (this.axis != null) {
825             this.axis.configure();
826         }
827        
828         if (getParent() != null) {
829             getParent().datasetChanged(event);
830         }
831         else {
832             super.datasetChanged(event);
833         }
834     }
835    
836     /**
837      * Notifies all registered listeners of a property change.
838      * <P>
839      * One source of property change events is the plot's m_Renderer.
840      *
841      * @param event information about the property change.
842      */

843     public void rendererChanged(RendererChangeEvent event) {
844         notifyListeners(new PlotChangeEvent(this));
845     }
846    
847     /**
848      * Returns the number of series in the dataset for this plot. If the
849      * dataset is <code>null</code>, the method returns 0.
850      *
851      * @return The series count.
852      */

853     public int getSeriesCount() {
854         int result = 0;
855        
856         if (this.dataset != null) {
857             result = this.dataset.getSeriesCount();
858         }
859         return result;
860     }
861    
862     /**
863      * Returns the legend items for the plot. Each legend item is generated by
864      * the plot's m_Renderer, since the m_Renderer is responsible for the visual
865      * representation of the data.
866      *
867      * @return The legend items.
868      */

869     public LegendItemCollection getLegendItems() {
870         LegendItemCollection result = new LegendItemCollection();
871        
872         // get the legend items for the main m_Dataset...
873
if (this.dataset != null) {
874             if (this.renderer != null) {
875                 int seriesCount = this.dataset.getSeriesCount();
876                 for (int i = 0; i < seriesCount; i++) {
877                     LegendItem item = this.renderer.getLegendItem(i);
878                     result.add(item);
879                 }
880             }
881         }
882         return result;
883     }
884    
885     /**
886      * Tests this plot for equality with another object.
887      *
888      * @param obj the object (<code>null</code> permitted).
889      *
890      * @return <code>true</code> or <code>false</code>.
891      */

892     public boolean equals(Object JavaDoc obj) {
893         if (obj == this) {
894             return true;
895         }
896         if (!(obj instanceof PolarPlot)) {
897             return false;
898         }
899         if (!super.equals(obj)) {
900             return false;
901         }
902         PolarPlot that = (PolarPlot) obj;
903         if (!ObjectUtilities.equal(this.axis, that.axis)) {
904             return false;
905         }
906         if (!ObjectUtilities.equal(this.renderer, that.renderer)) {
907             return false;
908         }
909         if (this.angleGridlinesVisible != that.angleGridlinesVisible) {
910             return false;
911         }
912         if (this.angleLabelsVisible != that.angleLabelsVisible) {
913             return false;
914         }
915         if (!this.angleLabelFont.equals(that.angleLabelFont)) {
916             return false;
917         }
918         if (!PaintUtilities.equal(this.angleLabelPaint, that.angleLabelPaint)) {
919             return false;
920         }
921         if (!ObjectUtilities.equal(this.angleGridlineStroke,
922                 that.angleGridlineStroke)) {
923             return false;
924         }
925         if (!PaintUtilities.equal(
926             this.angleGridlinePaint, that.angleGridlinePaint
927         )) {
928             return false;
929         }
930         if (this.radiusGridlinesVisible != that.radiusGridlinesVisible) {
931             return false;
932         }
933         if (!ObjectUtilities.equal(this.radiusGridlineStroke,
934                 that.radiusGridlineStroke)) {
935             return false;
936         }
937         if (!PaintUtilities.equal(this.radiusGridlinePaint,
938                 that.radiusGridlinePaint)) {
939             return false;
940         }
941         return true;
942     }
943    
944     /**
945      * Returns a clone of the plot.
946      *
947      * @return A clone.
948      *
949      * @throws CloneNotSupportedException this can occur if some component of
950      * the plot cannot be cloned.
951      */

952     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
953       
954         PolarPlot clone = (PolarPlot) super.clone();
955         if (this.axis != null) {
956             clone.axis = (ValueAxis) ObjectUtilities.clone(this.axis);
957             clone.axis.setPlot(clone);
958             clone.axis.addChangeListener(clone);
959         }
960       
961         if (clone.dataset != null) {
962             clone.dataset.addChangeListener(clone);
963         }
964       
965         if (this.renderer != null) {
966             clone.renderer
967                 = (PolarItemRenderer) ObjectUtilities.clone(this.renderer);
968         }
969        
970         return clone;
971     }
972    
973     /**
974      * Provides serialization support.
975      *
976      * @param stream the output stream.
977      *
978      * @throws IOException if there is an I/O error.
979      */

980     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
981         stream.defaultWriteObject();
982         SerialUtilities.writeStroke(this.angleGridlineStroke, stream);
983         SerialUtilities.writePaint(this.angleGridlinePaint, stream);
984         SerialUtilities.writeStroke(this.radiusGridlineStroke, stream);
985         SerialUtilities.writePaint(this.radiusGridlinePaint, stream);
986     }
987    
988     /**
989      * Provides serialization support.
990      *
991      * @param stream the input stream.
992      *
993      * @throws IOException if there is an I/O error.
994      * @throws ClassNotFoundException if there is a classpath problem.
995      */

996     private void readObject(ObjectInputStream JavaDoc stream)
997         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
998       
999         stream.defaultReadObject();
1000        this.angleGridlineStroke = SerialUtilities.readStroke(stream);
1001        this.angleGridlinePaint = SerialUtilities.readPaint(stream);
1002        this.radiusGridlineStroke = SerialUtilities.readStroke(stream);
1003        this.radiusGridlinePaint = SerialUtilities.readPaint(stream);
1004      
1005        if (this.axis != null) {
1006            this.axis.setPlot(this);
1007            this.axis.addChangeListener(this);
1008        }
1009      
1010        if (this.dataset != null) {
1011            this.dataset.addChangeListener(this);
1012        }
1013    }
1014   
1015    /**
1016     * This method is required by the {@link Zoomable} interface, but since
1017     * the plot does not have any domain axes, it does nothing.
1018     *
1019     * @param factor the zoom factor.
1020     * @param state the plot state.
1021     * @param source the source point (in Java2D coordinates).
1022     */

1023    public void zoomDomainAxes(double factor, PlotRenderingInfo state,
1024                               Point2D JavaDoc source) {
1025        // do nothing
1026
}
1027   
1028    /**
1029     * This method is required by the {@link Zoomable} interface, but since
1030     * the plot does not have any domain axes, it does nothing.
1031     *
1032     * @param lowerPercent the new lower bound.
1033     * @param upperPercent the new upper bound.
1034     * @param state the plot state.
1035     * @param source the source point (in Java2D coordinates).
1036     */

1037    public void zoomDomainAxes(double lowerPercent, double upperPercent,
1038                               PlotRenderingInfo state, Point2D JavaDoc source) {
1039        // do nothing
1040
}
1041   
1042    /**
1043     * Multiplies the range on the range axis/axes by the specified factor.
1044     *
1045     * @param factor the zoom factor.
1046     * @param state the plot state.
1047     * @param source the source point (in Java2D coordinates).
1048     */

1049    public void zoomRangeAxes(double factor, PlotRenderingInfo state,
1050                              Point2D JavaDoc source) {
1051        zoom(factor);
1052    }
1053   
1054    /**
1055     * Zooms in on the range axes.
1056     *
1057     * @param lowerPercent the new lower bound.
1058     * @param upperPercent the new upper bound.
1059     * @param state the plot state.
1060     * @param source the source point (in Java2D coordinates).
1061     */

1062    public void zoomRangeAxes(double lowerPercent, double upperPercent,
1063                              PlotRenderingInfo state, Point2D JavaDoc source) {
1064        zoom((upperPercent + lowerPercent) / 2.0);
1065    }
1066
1067    /**
1068     * Returns <code>true</code>.
1069     *
1070     * @return A boolean.
1071     */

1072    public boolean isDomainZoomable() {
1073        return false;
1074    }
1075    
1076    /**
1077     * Returns <code>true</code>.
1078     *
1079     * @return A boolean.
1080     */

1081    public boolean isRangeZoomable() {
1082        return true;
1083    }
1084    
1085    /**
1086     * Returns the orientation of the plot.
1087     *
1088     * @return The orientation.
1089     */

1090    public PlotOrientation getOrientation() {
1091        return PlotOrientation.HORIZONTAL;
1092    }
1093
1094    /**
1095     * Returns the upper bound of the radius axis.
1096     *
1097     * @return The upper bound.
1098     */

1099    public double getMaxRadius() {
1100        return this.axis.getUpperBound();
1101    }
1102
1103    /**
1104     * Translates a (theta, radius) pair into Java2D coordinates.
1105     *
1106     * @param angleDegrees the angle in degrees.
1107     * @param radius the radius.
1108     * @param dataArea the data area.
1109     *
1110     * @return A point in Java2D space.
1111     */

1112    public Point JavaDoc translateValueThetaRadiusToJava2D(double angleDegrees,
1113                                                   double radius,
1114                                                   Rectangle2D JavaDoc dataArea) {
1115       
1116        double radians = Math.toRadians(angleDegrees - 90.0);
1117      
1118        double minx = dataArea.getMinX() + MARGIN;
1119        double maxx = dataArea.getMaxX() - MARGIN;
1120        double miny = dataArea.getMinY() + MARGIN;
1121        double maxy = dataArea.getMaxY() - MARGIN;
1122      
1123        double lengthX = maxx - minx;
1124        double lengthY = maxy - miny;
1125        double length = Math.min(lengthX, lengthY);
1126      
1127        double midX = minx + lengthX / 2.0;
1128        double midY = miny + lengthY / 2.0;
1129      
1130        double axisMin = this.axis.getLowerBound();
1131        double axisMax = getMaxRadius();
1132
1133        double xv = length / 2.0 * Math.cos(radians);
1134        double yv = length / 2.0 * Math.sin(radians);
1135
1136        float x = (float) (midX + (xv * (radius - axisMin)
1137                / (axisMax - axisMin)));
1138        float y = (float) (midY + (yv * (radius - axisMin)
1139                / (axisMax - axisMin)));
1140      
1141        int ix = Math.round(x);
1142        int iy = Math.round(y);
1143      
1144        Point JavaDoc p = new Point JavaDoc(ix, iy);
1145        return p;
1146        
1147    }
1148    
1149}
1150
Popular Tags