KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, 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 License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ----------------
27  * ContourPlot.java
28  * ----------------
29  * (C) Copyright 2002-2005, by David M. O'Donnell and Contributors.
30  *
31  * Original Author: David M. O'Donnell;
32  * Contributor(s): David Gilbert (for Object Refinery Limited);
33  * Arnaud Lelievre;
34  * Nicolas Brodu;
35  *
36  * $Id: ContourPlot.java,v 1.16 2005/05/19 14:03:41 mungady Exp $
37  *
38  * Changes
39  * -------
40  * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
41  * 14-Jan-2003 : Added crosshair attributes (DG);
42  * 23-Jan-2003 : Removed two constructors (DG);
43  * 21-Mar-2003 : Bug fix 701744 (DG);
44  * 26-Mar-2003 : Implemented Serializable (DG);
45  * 09-Jul-2003 : Changed ColorBar from extending axis classes to enclosing
46  * them (DG);
47  * 05-Aug-2003 : Applied changes in bug report 780298 (DG);
48  * 08-Sep-2003 : Added internationalization via use of properties
49  * resourceBundle (RFE 690236) (AL);
50  * 11-Sep-2003 : Cloning support (NB);
51  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
52  * 17-Jan-2004 : Removed references to DefaultContourDataset class, replaced
53  * with ContourDataset interface (with changes to the interface).
54  * See bug 741048 (DG);
55  * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
56  * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG);
57  * 06-Oct-2004 : Updated for changes in DatasetUtilities class (DG);
58  * 11-Nov-2004 : Renamed zoom methods to match ValueAxisPlot interface (DG);
59  * 25-Nov-2004 : Small update to clone() implementation (DG);
60  * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
61  * 05-May-2005 : Updated draw() method parameters (DG);
62  *
63  */

64
65 package org.jfree.chart.plot;
66
67 import java.awt.AlphaComposite JavaDoc;
68 import java.awt.Composite JavaDoc;
69 import java.awt.Graphics2D JavaDoc;
70 import java.awt.Paint JavaDoc;
71 import java.awt.RenderingHints JavaDoc;
72 import java.awt.Shape JavaDoc;
73 import java.awt.Stroke JavaDoc;
74 import java.awt.geom.Ellipse2D JavaDoc;
75 import java.awt.geom.GeneralPath JavaDoc;
76 import java.awt.geom.Line2D JavaDoc;
77 import java.awt.geom.Point2D JavaDoc;
78 import java.awt.geom.Rectangle2D JavaDoc;
79 import java.awt.geom.RectangularShape JavaDoc;
80 import java.beans.PropertyChangeEvent JavaDoc;
81 import java.beans.PropertyChangeListener JavaDoc;
82 import java.io.Serializable JavaDoc;
83 import java.util.Iterator JavaDoc;
84 import java.util.List JavaDoc;
85 import java.util.ResourceBundle JavaDoc;
86
87 import org.jfree.chart.ClipPath;
88 import org.jfree.chart.annotations.XYAnnotation;
89 import org.jfree.chart.axis.AxisSpace;
90 import org.jfree.chart.axis.ColorBar;
91 import org.jfree.chart.axis.NumberAxis;
92 import org.jfree.chart.axis.ValueAxis;
93 import org.jfree.chart.entity.ContourEntity;
94 import org.jfree.chart.entity.EntityCollection;
95 import org.jfree.chart.event.AxisChangeEvent;
96 import org.jfree.chart.event.PlotChangeEvent;
97 import org.jfree.chart.labels.ContourToolTipGenerator;
98 import org.jfree.chart.labels.StandardContourToolTipGenerator;
99 import org.jfree.chart.urls.XYURLGenerator;
100 import org.jfree.data.Range;
101 import org.jfree.data.contour.ContourDataset;
102 import org.jfree.data.general.DatasetChangeEvent;
103 import org.jfree.data.general.DatasetUtilities;
104 import org.jfree.ui.RectangleEdge;
105 import org.jfree.ui.RectangleInsets;
106 import org.jfree.util.ObjectUtilities;
107
108 /**
109  * A class for creating shaded contours.
110  *
111  * @author David M. O'Donnell
112  */

113 public class ContourPlot extends Plot implements ContourValuePlot,
114                                                  ValueAxisPlot,
115                                                  PropertyChangeListener JavaDoc,
116                                                  Serializable JavaDoc,
117                                                  Cloneable JavaDoc {
118
119     /** For serialization. */
120     private static final long serialVersionUID = 7861072556590502247L;
121     
122     /** The default insets. */
123     protected static final RectangleInsets DEFAULT_INSETS
124         = new RectangleInsets(2.0, 2.0, 100.0, 10.0);
125
126     /** The domain axis (used for the x-values). */
127     private ValueAxis domainAxis;
128
129     /** The range axis (used for the y-values). */
130     private ValueAxis rangeAxis;
131
132     /** The dataset. */
133     private ContourDataset dataset;
134     
135     /** The colorbar axis (used for the z-values). */
136     private ColorBar colorBar = null;
137
138     /** The color bar location. */
139     private RectangleEdge colorBarLocation;
140     
141     /** A flag that controls whether or not a domain crosshair is drawn..*/
142     private boolean domainCrosshairVisible;
143
144     /** The domain crosshair value. */
145     private double domainCrosshairValue;
146
147     /** The pen/brush used to draw the crosshair (if any). */
148     private transient Stroke JavaDoc domainCrosshairStroke;
149
150     /** The color used to draw the crosshair (if any). */
151     private transient Paint JavaDoc domainCrosshairPaint;
152
153     /**
154      * A flag that controls whether or not the crosshair locks onto actual data
155      * points.
156      */

157     private boolean domainCrosshairLockedOnData = true;
158
159     /** A flag that controls whether or not a range crosshair is drawn..*/
160     private boolean rangeCrosshairVisible;
161
162     /** The range crosshair value. */
163     private double rangeCrosshairValue;
164
165     /** The pen/brush used to draw the crosshair (if any). */
166     private transient Stroke JavaDoc rangeCrosshairStroke;
167
168     /** The color used to draw the crosshair (if any). */
169     private transient Paint JavaDoc rangeCrosshairPaint;
170
171     /**
172      * A flag that controls whether or not the crosshair locks onto actual data
173      * points.
174      */

175     private boolean rangeCrosshairLockedOnData = true;
176
177     /** A list of markers (optional) for the domain axis. */
178     private List JavaDoc domainMarkers;
179
180     /** A list of markers (optional) for the range axis. */
181     private List JavaDoc rangeMarkers;
182
183     /** A list of annotations (optional) for the plot. */
184     private List JavaDoc annotations;
185
186     /** The tool tip generator. */
187     private ContourToolTipGenerator toolTipGenerator;
188
189     /** The URL text generator. */
190     private XYURLGenerator urlGenerator;
191
192     /**
193      * Controls whether data are render as filled rectangles or rendered as
194      * points
195      */

196     private boolean renderAsPoints = false;
197
198     /**
199      * Size of points rendered when renderAsPoints = true. Size is relative to
200      * dataArea
201      */

202     private double ptSizePct = 0.05;
203
204     /** Contains the a ClipPath to "trim" the contours. */
205     private transient ClipPath clipPath = null;
206
207     /** Set to Paint to represent missing values. */
208     private transient Paint JavaDoc missingPaint = null;
209
210     /** The resourceBundle for the localization. */
211     protected static ResourceBundle JavaDoc localizationResources =
212         ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
213
214     /**
215      * Constructs a contour plot with the specified axes (other attributes take
216      * default values).
217      *
218      * @param dataset The dataset.
219      * @param domainAxis The domain axis.
220      * @param rangeAxis The range axis.
221      * @param colorBar The z-axis axis.
222     */

223     public ContourPlot(ContourDataset dataset,
224                        ValueAxis domainAxis, ValueAxis rangeAxis,
225                        ColorBar colorBar) {
226
227         super();
228
229         this.dataset = dataset;
230         if (dataset != null) {
231             dataset.addChangeListener(this);
232         }
233         
234         this.domainAxis = domainAxis;
235         if (domainAxis != null) {
236             domainAxis.setPlot(this);
237             domainAxis.addChangeListener(this);
238         }
239
240         this.rangeAxis = rangeAxis;
241         if (rangeAxis != null) {
242             rangeAxis.setPlot(this);
243             rangeAxis.addChangeListener(this);
244         }
245
246         this.colorBar = colorBar;
247         if (colorBar != null) {
248             colorBar.getAxis().setPlot(this);
249             colorBar.getAxis().addChangeListener(this);
250             colorBar.configure(this);
251         }
252         this.colorBarLocation = RectangleEdge.LEFT;
253
254         this.toolTipGenerator = new StandardContourToolTipGenerator();
255
256     }
257
258     /**
259      * Returns the color bar location.
260      *
261      * @return The color bar location.
262      */

263     public RectangleEdge getColorBarLocation() {
264         return this.colorBarLocation;
265     }
266     
267     /**
268      * Sets the color bar location and sends a {@link PlotChangeEvent} to all
269      * registered listeners.
270      *
271      * @param edge the location.
272      */

273     public void setColorBarLocation(RectangleEdge edge) {
274         this.colorBarLocation = edge;
275         notifyListeners(new PlotChangeEvent(this));
276     }
277     
278     /**
279      * Returns the primary dataset for the plot.
280      *
281      * @return The primary dataset (possibly <code>null</code>).
282      */

283     public ContourDataset getDataset() {
284         return this.dataset;
285     }
286     
287     /**
288      * Sets the dataset for the plot, replacing the existing dataset if there
289      * is one.
290      *
291      * @param dataset the dataset (<code>null</code> permitted).
292      */

293     public void setDataset(ContourDataset dataset) {
294         
295         // if there is an existing dataset, remove the plot from the list of
296
// change listeners...
297
ContourDataset existing = this.dataset;
298         if (existing != null) {
299             existing.removeChangeListener(this);
300         }
301
302         // set the new dataset, and register the chart as a change listener...
303
this.dataset = dataset;
304         if (dataset != null) {
305             setDatasetGroup(dataset.getGroup());
306             dataset.addChangeListener(this);
307         }
308
309         // send a dataset change event to self...
310
DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
311         datasetChanged(event);
312         
313     }
314
315     /**
316      * Returns the domain axis for the plot.
317      *
318      * @return The domain axis.
319      */

320     public ValueAxis getDomainAxis() {
321
322         ValueAxis result = this.domainAxis;
323
324         return result;
325
326     }
327
328     /**
329      * Sets the domain axis for the plot (this must be compatible with the plot
330      * type or an exception is thrown).
331      *
332      * @param axis The new axis.
333      */

334     public void setDomainAxis(ValueAxis axis) {
335
336         if (isCompatibleDomainAxis(axis)) {
337
338             if (axis != null) {
339                 axis.setPlot(this);
340                 axis.addChangeListener(this);
341             }
342
343             // plot is likely registered as a listener with the existing axis...
344
if (this.domainAxis != null) {
345                 this.domainAxis.removeChangeListener(this);
346             }
347
348             this.domainAxis = axis;
349             notifyListeners(new PlotChangeEvent(this));
350
351         }
352
353     }
354
355     /**
356      * Returns the range axis for the plot.
357      *
358      * @return The range axis.
359      */

360     public ValueAxis getRangeAxis() {
361
362         ValueAxis result = this.rangeAxis;
363
364         return result;
365
366     }
367
368     /**
369      * Sets the range axis for the plot.
370      * <P>
371      * An exception is thrown if the new axis and the plot are not mutually
372      * compatible.
373      *
374      * @param axis The new axis (null permitted).
375      */

376     public void setRangeAxis(ValueAxis axis) {
377
378         if (axis != null) {
379             axis.setPlot(this);
380             axis.addChangeListener(this);
381         }
382
383         // plot is likely registered as a listener with the existing axis...
384
if (this.rangeAxis != null) {
385             this.rangeAxis.removeChangeListener(this);
386         }
387
388         this.rangeAxis = axis;
389         notifyListeners(new PlotChangeEvent(this));
390
391     }
392
393     /**
394      * Sets the colorbar for the plot.
395      *
396      * @param axis The new axis (null permitted).
397      */

398     public void setColorBarAxis(ColorBar axis) {
399
400         this.colorBar = axis;
401         notifyListeners(new PlotChangeEvent(this));
402
403     }
404
405     /**
406      * Adds a marker for the domain axis.
407      * <P>
408      * Typically a marker will be drawn by the renderer as a line perpendicular
409      * to the range axis, however this is entirely up to the renderer.
410      *
411      * @param marker the marker.
412      */

413     public void addDomainMarker(Marker marker) {
414
415         if (this.domainMarkers == null) {
416             this.domainMarkers = new java.util.ArrayList JavaDoc();
417         }
418         this.domainMarkers.add(marker);
419         notifyListeners(new PlotChangeEvent(this));
420
421     }
422
423     /**
424      * Clears all the domain markers.
425      */

426     public void clearDomainMarkers() {
427         if (this.domainMarkers != null) {
428             this.domainMarkers.clear();
429             notifyListeners(new PlotChangeEvent(this));
430         }
431     }
432
433     /**
434      * Adds a marker for the range axis.
435      * <P>
436      * Typically a marker will be drawn by the renderer as a line perpendicular
437      * to the range axis, however this is entirely up to the renderer.
438      *
439      * @param marker The marker.
440      */

441     public void addRangeMarker(Marker marker) {
442
443         if (this.rangeMarkers == null) {
444             this.rangeMarkers = new java.util.ArrayList JavaDoc();
445         }
446         this.rangeMarkers.add(marker);
447         notifyListeners(new PlotChangeEvent(this));
448
449     }
450
451     /**
452      * Clears all the range markers.
453      */

454     public void clearRangeMarkers() {
455         if (this.rangeMarkers != null) {
456             this.rangeMarkers.clear();
457             notifyListeners(new PlotChangeEvent(this));
458         }
459     }
460
461     /**
462      * Adds an annotation to the plot.
463      *
464      * @param annotation the annotation.
465      */

466     public void addAnnotation(XYAnnotation annotation) {
467
468         if (this.annotations == null) {
469             this.annotations = new java.util.ArrayList JavaDoc();
470         }
471         this.annotations.add(annotation);
472         notifyListeners(new PlotChangeEvent(this));
473
474     }
475
476     /**
477      * Clears all the annotations.
478      */

479     public void clearAnnotations() {
480         if (this.annotations != null) {
481             this.annotations.clear();
482             notifyListeners(new PlotChangeEvent(this));
483         }
484     }
485
486     /**
487      * Checks the compatibility of a domain axis, returning true if the axis is
488      * compatible with the plot, and false otherwise.
489      *
490      * @param axis The proposed axis.
491      *
492      * @return <code>true</code> if the axis is compatible with the plot.
493      */

494     public boolean isCompatibleDomainAxis(ValueAxis axis) {
495
496         return true;
497
498     }
499
500     /**
501      * Draws the plot on a Java 2D graphics device (such as the screen or a
502      * printer).
503      * <P>
504      * The optional <code>info</code> argument collects information about the
505      * rendering of the plot (dimensions, tooltip information etc). Just pass
506      * in <code>null</code> if you do not need this information.
507      *
508      * @param g2 the graphics device.
509      * @param area the area within which the plot (including axis labels)
510      * should be drawn.
511      * @param anchor the anchor point (<code>null</code> permitted).
512      * @param parentState the state from the parent plot, if there is one.
513      * @param info collects chart drawing information (<code>null</code>
514      * permitted).
515      */

516     public void draw(Graphics2D JavaDoc g2, Rectangle2D JavaDoc area, Point2D JavaDoc anchor,
517                      PlotState parentState,
518                      PlotRenderingInfo info) {
519
520         // if the plot area is too small, just return...
521
boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW);
522         boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW);
523         if (b1 || b2) {
524             return;
525         }
526
527         // record the plot area...
528
if (info != null) {
529             info.setPlotArea(area);
530         }
531
532         // adjust the drawing area for plot insets (if any)...
533
RectangleInsets insets = getInsets();
534         insets.trim(area);
535
536         AxisSpace space = new AxisSpace();
537         
538         space = this.domainAxis.reserveSpace(
539             g2, this, area, RectangleEdge.BOTTOM, space
540         );
541         space = this.rangeAxis.reserveSpace(
542             g2, this, area, RectangleEdge.LEFT, space
543         );
544
545         Rectangle2D JavaDoc estimatedDataArea = space.shrink(area, null);
546         
547         AxisSpace space2 = new AxisSpace();
548         space2 = this.colorBar.reserveSpace(
549             g2, this, area, estimatedDataArea, this.colorBarLocation,
550             space2
551         );
552         Rectangle2D JavaDoc adjustedPlotArea = space2.shrink(area, null);
553         
554         Rectangle2D JavaDoc dataArea = space.shrink(adjustedPlotArea, null);
555
556         Rectangle2D JavaDoc colorBarArea = space2.reserved(
557             area, this.colorBarLocation
558         );
559
560         // additional dataArea modifications
561
if (getDataAreaRatio() != 0.0) { //check whether modification is
562
double ratio = getDataAreaRatio();
563             Rectangle2D JavaDoc tmpDataArea = (Rectangle2D JavaDoc) dataArea.clone();
564             double h = tmpDataArea.getHeight();
565             double w = tmpDataArea.getWidth();
566
567             if (ratio > 0) { // ratio represents pixels
568
if (w * ratio <= h) {
569                     h = ratio * w;
570                 }
571                 else {
572                     w = h / ratio;
573                 }
574             }
575             else { // ratio represents axis units
576
ratio *= -1.0;
577                 double xLength = getDomainAxis().getRange().getLength();
578                 double yLength = getRangeAxis().getRange().getLength();
579                 double unitRatio = yLength / xLength;
580
581                 ratio = unitRatio * ratio;
582
583                 if (w * ratio <= h) {
584                     h = ratio * w;
585                 }
586                 else {
587                     w = h / ratio;
588                 }
589             }
590
591             dataArea.setRect(
592                 tmpDataArea.getX() + tmpDataArea.getWidth() / 2 - w / 2,
593                 tmpDataArea.getY(), w, h
594             );
595         }
596
597         if (info != null) {
598             info.setDataArea(dataArea);
599         }
600
601         CrosshairState crosshairState = new CrosshairState();
602         crosshairState.setCrosshairDistance(Double.POSITIVE_INFINITY);
603
604         // draw the plot background...
605
drawBackground(g2, dataArea);
606
607         double cursor = dataArea.getMaxY();
608         if (this.domainAxis != null) {
609             this.domainAxis.draw(
610                 g2, cursor, adjustedPlotArea, dataArea, RectangleEdge.BOTTOM,
611                 info
612             );
613         }
614
615         if (this.rangeAxis != null) {
616             cursor = dataArea.getMinX();
617             this.rangeAxis.draw(
618                 g2, cursor, adjustedPlotArea, dataArea, RectangleEdge.LEFT, info
619             );
620         }
621
622         if (this.colorBar != null) {
623             cursor = 0.0;
624             cursor = this.colorBar.draw(
625                 g2, cursor, adjustedPlotArea, dataArea, colorBarArea,
626                 this.colorBarLocation
627             );
628         }
629         Shape JavaDoc originalClip = g2.getClip();
630         Composite JavaDoc originalComposite = g2.getComposite();
631
632         g2.clip(dataArea);
633         g2.setComposite(AlphaComposite.getInstance(
634             AlphaComposite.SRC_OVER, getForegroundAlpha())
635         );
636         render(g2, dataArea, info, crosshairState);
637
638         if (this.domainMarkers != null) {
639             Iterator JavaDoc iterator = this.domainMarkers.iterator();
640             while (iterator.hasNext()) {
641                 Marker marker = (Marker) iterator.next();
642                 drawDomainMarker(g2, this, getDomainAxis(), marker, dataArea);
643             }
644         }
645
646         if (this.rangeMarkers != null) {
647             Iterator JavaDoc iterator = this.rangeMarkers.iterator();
648             while (iterator.hasNext()) {
649                 Marker marker = (Marker) iterator.next();
650                 drawRangeMarker(g2, this, getRangeAxis(), marker, dataArea);
651             }
652         }
653
654 // TO DO: these annotations only work with XYPlot, see if it is possible to
655
// make ContourPlot a subclass of XYPlot (DG);
656

657 // // draw the annotations...
658
// if (this.annotations != null) {
659
// Iterator iterator = this.annotations.iterator();
660
// while (iterator.hasNext()) {
661
// Annotation annotation = (Annotation) iterator.next();
662
// if (annotation instanceof XYAnnotation) {
663
// XYAnnotation xya = (XYAnnotation) annotation;
664
// // get the annotation to draw itself...
665
// xya.draw(g2, this, dataArea, getDomainAxis(),
666
// getRangeAxis());
667
// }
668
// }
669
// }
670

671         g2.setClip(originalClip);
672         g2.setComposite(originalComposite);
673         drawOutline(g2, dataArea);
674
675     }
676
677     /**
678      * Draws a representation of the data within the dataArea region, using the
679      * current renderer.
680      * <P>
681      * The <code>info</code> and <code>crosshairState</code> arguments may be
682      * <code>null</code>.
683      *
684      * @param g2 the graphics device.
685      * @param dataArea the region in which the data is to be drawn.
686      * @param info an optional object for collection dimension information.
687      * @param crosshairState an optional object for collecting crosshair info.
688      */

689     public void render(Graphics2D JavaDoc g2, Rectangle2D JavaDoc dataArea,
690                        PlotRenderingInfo info, CrosshairState crosshairState) {
691
692         // now get the data and plot it (the visual representation will depend
693
// on the renderer that has been set)...
694
ContourDataset data = getDataset();
695         if (data != null) {
696
697             ColorBar zAxis = getColorBar();
698
699             if (this.clipPath != null) {
700                 GeneralPath JavaDoc clipper = getClipPath().draw(
701                     g2, dataArea, this.domainAxis, this.rangeAxis
702                 );
703                 if (this.clipPath.isClip()) {
704                     g2.clip(clipper);
705                 }
706             }
707
708             if (this.renderAsPoints) {
709                 pointRenderer(g2, dataArea, info, this,
710                         this.domainAxis, this.rangeAxis, zAxis,
711                               data, crosshairState);
712             }
713             else {
714                 contourRenderer(g2, dataArea, info, this,
715                         this.domainAxis, this.rangeAxis, zAxis,
716                                 data, crosshairState);
717             }
718
719             // draw vertical crosshair if required...
720
setDomainCrosshairValue(crosshairState.getCrosshairX(), false);
721             if (isDomainCrosshairVisible()) {
722                 drawVerticalLine(g2, dataArea,
723                                  getDomainCrosshairValue(),
724                                  getDomainCrosshairStroke(),
725                                  getDomainCrosshairPaint());
726             }
727
728             // draw horizontal crosshair if required...
729
setRangeCrosshairValue(crosshairState.getCrosshairY(), false);
730             if (isRangeCrosshairVisible()) {
731                 drawHorizontalLine(g2, dataArea,
732                                    getRangeCrosshairValue(),
733                                    getRangeCrosshairStroke(),
734                                    getRangeCrosshairPaint());
735             }
736
737         }
738         else if (this.clipPath != null) {
739             getClipPath().draw(g2, dataArea, this.domainAxis, this.rangeAxis);
740         }
741
742     }
743
744     /**
745      * Fills the plot.
746      *
747      * @param g2 the graphics device.
748      * @param dataArea the area within which the data is being drawn.
749      * @param info collects information about the drawing.
750      * @param plot the plot (can be used to obtain standard color
751      * information etc).
752      * @param horizontalAxis the domain (horizontal) axis.
753      * @param verticalAxis the range (vertical) axis.
754      * @param colorBar the color bar axis.
755      * @param data the dataset.
756      * @param crosshairState information about crosshairs on a plot.
757      */

758     public void contourRenderer(Graphics2D JavaDoc g2,
759                                 Rectangle2D JavaDoc dataArea,
760                                 PlotRenderingInfo info,
761                                 ContourPlot plot,
762                                 ValueAxis horizontalAxis,
763                                 ValueAxis verticalAxis,
764                                 ColorBar colorBar,
765                                 ContourDataset data,
766                                 CrosshairState crosshairState) {
767
768         // setup for collecting optional entity info...
769
Rectangle2D.Double JavaDoc entityArea = null;
770         EntityCollection entities = null;
771         if (info != null) {
772             entities = info.getOwner().getEntityCollection();
773         }
774
775         Rectangle2D.Double JavaDoc rect = null;
776         rect = new Rectangle2D.Double JavaDoc();
777
778         //turn off anti-aliasing when filling rectangles
779
Object JavaDoc antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
780         g2.setRenderingHint(
781             RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF
782         );
783
784         // get the data points
785
Number JavaDoc[] xNumber = data.getXValues();
786         Number JavaDoc[] yNumber = data.getYValues();
787         Number JavaDoc[] zNumber = data.getZValues();
788
789         double[] x = new double[xNumber.length];
790         double[] y = new double[yNumber.length];
791
792         for (int i = 0; i < x.length; i++) {
793             x[i] = xNumber[i].doubleValue();
794             y[i] = yNumber[i].doubleValue();
795         }
796
797         int[] xIndex = data.indexX();
798         int[] indexX = data.getXIndices();
799         boolean vertInverted = ((NumberAxis) verticalAxis).isInverted();
800         boolean horizInverted = false;
801         if (horizontalAxis instanceof NumberAxis) {
802             horizInverted = ((NumberAxis) horizontalAxis).isInverted();
803         }
804         double transX = 0.0;
805         double transXm1 = 0.0;
806         double transXp1 = 0.0;
807         double transDXm1 = 0.0;
808         double transDXp1 = 0.0;
809         double transDX = 0.0;
810         double transY = 0.0;
811         double transYm1 = 0.0;
812         double transYp1 = 0.0;
813         double transDYm1 = 0.0;
814         double transDYp1 = 0.0;
815         double transDY = 0.0;
816         int iMax = xIndex[xIndex.length - 1];
817         for (int k = 0; k < x.length; k++) {
818             int i = xIndex[k];
819             if (indexX[i] == k) { // this is a new column
820
if (i == 0) {
821                     transX = horizontalAxis.valueToJava2D(
822                         x[k], dataArea, RectangleEdge.BOTTOM
823                     );
824                     transXm1 = transX;
825                     transXp1 = horizontalAxis.valueToJava2D(
826                         x[indexX[i + 1]], dataArea, RectangleEdge.BOTTOM
827                     );
828                     transDXm1 = Math.abs(0.5 * (transX - transXm1));
829                     transDXp1 = Math.abs(0.5 * (transX - transXp1));
830                 }
831                 else if (i == iMax) {
832                     transX = horizontalAxis.valueToJava2D(
833                         x[k], dataArea, RectangleEdge.BOTTOM
834                     );
835                     transXm1 = horizontalAxis.valueToJava2D(
836                         x[indexX[i - 1]], dataArea, RectangleEdge.BOTTOM
837                     );
838                     transXp1 = transX;
839                     transDXm1 = Math.abs(0.5 * (transX - transXm1));
840                     transDXp1 = Math.abs(0.5 * (transX - transXp1));
841                 }
842                 else {
843                     transX = horizontalAxis.valueToJava2D(
844                         x[k], dataArea, RectangleEdge.BOTTOM
845                     );
846                     transXp1 = horizontalAxis.valueToJava2D(
847                         x[indexX[i + 1]], dataArea, RectangleEdge.BOTTOM
848                     );
849                     transDXm1 = transDXp1;
850                     transDXp1 = Math.abs(0.5 * (transX - transXp1));
851                 }
852
853                 if (horizInverted) {
854                     transX -= transDXp1;
855                 }
856                 else {
857                     transX -= transDXm1;
858                 }
859
860                 transDX = transDXm1 + transDXp1;
861
862                 transY = verticalAxis.valueToJava2D(
863                     y[k], dataArea, RectangleEdge.LEFT
864                 );
865                 transYm1 = transY;
866 <