0001: /* ===========================================================
0002: * JFreeChart : a free chart library for the Java(tm) platform
0003: * ===========================================================
0004: *
0005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
0006: *
0007: * Project Info: http://www.jfree.org/jfreechart/index.html
0008: *
0009: * This library is free software; you can redistribute it and/or modify it
0010: * under the terms of the GNU Lesser General Public License as published by
0011: * the Free Software Foundation; either version 2.1 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * This library is distributed in the hope that it will be useful, but
0015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
0016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
0017: * License for more details.
0018: *
0019: * You should have received a copy of the GNU Lesser General Public
0020: * License along with this library; if not, write to the Free Software
0021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0022: * USA.
0023: *
0024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
0025: * in the United States and other countries.]
0026: *
0027: * ----------------
0028: * ContourPlot.java
0029: * ----------------
0030: * (C) Copyright 2002-2007, by David M. O'Donnell and Contributors.
0031: *
0032: * Original Author: David M. O'Donnell;
0033: * Contributor(s): David Gilbert (for Object Refinery Limited);
0034: * Arnaud Lelievre;
0035: * Nicolas Brodu;
0036: *
0037: * $Id: ContourPlot.java,v 1.16.2.5 2007/01/31 15:56:18 mungady Exp $
0038: *
0039: * Changes
0040: * -------
0041: * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG);
0042: * 14-Jan-2003 : Added crosshair attributes (DG);
0043: * 23-Jan-2003 : Removed two constructors (DG);
0044: * 21-Mar-2003 : Bug fix 701744 (DG);
0045: * 26-Mar-2003 : Implemented Serializable (DG);
0046: * 09-Jul-2003 : Changed ColorBar from extending axis classes to enclosing
0047: * them (DG);
0048: * 05-Aug-2003 : Applied changes in bug report 780298 (DG);
0049: * 08-Sep-2003 : Added internationalization via use of properties
0050: * resourceBundle (RFE 690236) (AL);
0051: * 11-Sep-2003 : Cloning support (NB);
0052: * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
0053: * 17-Jan-2004 : Removed references to DefaultContourDataset class, replaced
0054: * with ContourDataset interface (with changes to the interface).
0055: * See bug 741048 (DG);
0056: * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
0057: * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG);
0058: * 06-Oct-2004 : Updated for changes in DatasetUtilities class (DG);
0059: * 11-Nov-2004 : Renamed zoom methods to match ValueAxisPlot interface (DG);
0060: * 25-Nov-2004 : Small update to clone() implementation (DG);
0061: * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
0062: * 05-May-2005 : Updated draw() method parameters (DG);
0063: * 16-Jun-2005 : Added default constructor (DG);
0064: * 01-Sep-2005 : Moved dataAreaRatio from Plot to here (DG);
0065: * ------------- JFREECHART 1.0.x ---------------------------------------------
0066: * 31-Jan-2007 : Deprecated (DG);
0067: *
0068: */
0069:
0070: package org.jfree.chart.plot;
0071:
0072: import java.awt.AlphaComposite;
0073: import java.awt.Composite;
0074: import java.awt.Graphics2D;
0075: import java.awt.Paint;
0076: import java.awt.RenderingHints;
0077: import java.awt.Shape;
0078: import java.awt.Stroke;
0079: import java.awt.geom.Ellipse2D;
0080: import java.awt.geom.GeneralPath;
0081: import java.awt.geom.Line2D;
0082: import java.awt.geom.Point2D;
0083: import java.awt.geom.Rectangle2D;
0084: import java.awt.geom.RectangularShape;
0085: import java.beans.PropertyChangeEvent;
0086: import java.beans.PropertyChangeListener;
0087: import java.io.Serializable;
0088: import java.util.Iterator;
0089: import java.util.List;
0090: import java.util.ResourceBundle;
0091:
0092: import org.jfree.chart.ClipPath;
0093: import org.jfree.chart.annotations.XYAnnotation;
0094: import org.jfree.chart.axis.AxisSpace;
0095: import org.jfree.chart.axis.ColorBar;
0096: import org.jfree.chart.axis.NumberAxis;
0097: import org.jfree.chart.axis.ValueAxis;
0098: import org.jfree.chart.entity.ContourEntity;
0099: import org.jfree.chart.entity.EntityCollection;
0100: import org.jfree.chart.event.AxisChangeEvent;
0101: import org.jfree.chart.event.PlotChangeEvent;
0102: import org.jfree.chart.labels.ContourToolTipGenerator;
0103: import org.jfree.chart.labels.StandardContourToolTipGenerator;
0104: import org.jfree.chart.renderer.xy.XYBlockRenderer;
0105: import org.jfree.chart.urls.XYURLGenerator;
0106: import org.jfree.data.Range;
0107: import org.jfree.data.contour.ContourDataset;
0108: import org.jfree.data.general.DatasetChangeEvent;
0109: import org.jfree.data.general.DatasetUtilities;
0110: import org.jfree.ui.RectangleEdge;
0111: import org.jfree.ui.RectangleInsets;
0112: import org.jfree.util.ObjectUtilities;
0113:
0114: /**
0115: * A class for creating shaded contours.
0116: *
0117: * @deprecated This plot is no longer supported, please use {@link XYPlot} with
0118: * an {@link XYBlockRenderer}.
0119: */
0120: public class ContourPlot extends Plot implements ContourValuePlot,
0121: ValueAxisPlot, PropertyChangeListener, Serializable, Cloneable {
0122:
0123: /** For serialization. */
0124: private static final long serialVersionUID = 7861072556590502247L;
0125:
0126: /** The default insets. */
0127: protected static final RectangleInsets DEFAULT_INSETS = new RectangleInsets(
0128: 2.0, 2.0, 100.0, 10.0);
0129:
0130: /** The domain axis (used for the x-values). */
0131: private ValueAxis domainAxis;
0132:
0133: /** The range axis (used for the y-values). */
0134: private ValueAxis rangeAxis;
0135:
0136: /** The dataset. */
0137: private ContourDataset dataset;
0138:
0139: /** The colorbar axis (used for the z-values). */
0140: private ColorBar colorBar = null;
0141:
0142: /** The color bar location. */
0143: private RectangleEdge colorBarLocation;
0144:
0145: /** A flag that controls whether or not a domain crosshair is drawn..*/
0146: private boolean domainCrosshairVisible;
0147:
0148: /** The domain crosshair value. */
0149: private double domainCrosshairValue;
0150:
0151: /** The pen/brush used to draw the crosshair (if any). */
0152: private transient Stroke domainCrosshairStroke;
0153:
0154: /** The color used to draw the crosshair (if any). */
0155: private transient Paint domainCrosshairPaint;
0156:
0157: /**
0158: * A flag that controls whether or not the crosshair locks onto actual data
0159: * points.
0160: */
0161: private boolean domainCrosshairLockedOnData = true;
0162:
0163: /** A flag that controls whether or not a range crosshair is drawn..*/
0164: private boolean rangeCrosshairVisible;
0165:
0166: /** The range crosshair value. */
0167: private double rangeCrosshairValue;
0168:
0169: /** The pen/brush used to draw the crosshair (if any). */
0170: private transient Stroke rangeCrosshairStroke;
0171:
0172: /** The color used to draw the crosshair (if any). */
0173: private transient Paint rangeCrosshairPaint;
0174:
0175: /**
0176: * A flag that controls whether or not the crosshair locks onto actual data
0177: * points.
0178: */
0179: private boolean rangeCrosshairLockedOnData = true;
0180:
0181: /**
0182: * Defines dataArea rectangle as the ratio formed from dividing height by
0183: * width (of the dataArea). Modifies plot area calculations.
0184: * ratio>0 will attempt to layout the plot so that the
0185: * dataArea.height/dataArea.width = ratio.
0186: * ratio<0 will attempt to layout the plot so that the
0187: * dataArea.height/dataArea.width in plot units (not java2D units as when
0188: * ratio>0) = -1.*ratio.
0189: */
0190: //dmo
0191: private double dataAreaRatio = 0.0; //zero when the parameter is not set
0192:
0193: /** A list of markers (optional) for the domain axis. */
0194: private List domainMarkers;
0195:
0196: /** A list of markers (optional) for the range axis. */
0197: private List rangeMarkers;
0198:
0199: /** A list of annotations (optional) for the plot. */
0200: private List annotations;
0201:
0202: /** The tool tip generator. */
0203: private ContourToolTipGenerator toolTipGenerator;
0204:
0205: /** The URL text generator. */
0206: private XYURLGenerator urlGenerator;
0207:
0208: /**
0209: * Controls whether data are render as filled rectangles or rendered as
0210: * points
0211: */
0212: private boolean renderAsPoints = false;
0213:
0214: /**
0215: * Size of points rendered when renderAsPoints = true. Size is relative to
0216: * dataArea
0217: */
0218: private double ptSizePct = 0.05;
0219:
0220: /** Contains the a ClipPath to "trim" the contours. */
0221: private transient ClipPath clipPath = null;
0222:
0223: /** Set to Paint to represent missing values. */
0224: private transient Paint missingPaint = null;
0225:
0226: /** The resourceBundle for the localization. */
0227: protected static ResourceBundle localizationResources = ResourceBundle
0228: .getBundle("org.jfree.chart.plot.LocalizationBundle");
0229:
0230: /**
0231: * Creates a new plot with no dataset or axes.
0232: */
0233: public ContourPlot() {
0234: this (null, null, null, null);
0235: }
0236:
0237: /**
0238: * Constructs a contour plot with the specified axes (other attributes take
0239: * default values).
0240: *
0241: * @param dataset The dataset.
0242: * @param domainAxis The domain axis.
0243: * @param rangeAxis The range axis.
0244: * @param colorBar The z-axis axis.
0245: */
0246: public ContourPlot(ContourDataset dataset, ValueAxis domainAxis,
0247: ValueAxis rangeAxis, ColorBar colorBar) {
0248:
0249: super ();
0250:
0251: this .dataset = dataset;
0252: if (dataset != null) {
0253: dataset.addChangeListener(this );
0254: }
0255:
0256: this .domainAxis = domainAxis;
0257: if (domainAxis != null) {
0258: domainAxis.setPlot(this );
0259: domainAxis.addChangeListener(this );
0260: }
0261:
0262: this .rangeAxis = rangeAxis;
0263: if (rangeAxis != null) {
0264: rangeAxis.setPlot(this );
0265: rangeAxis.addChangeListener(this );
0266: }
0267:
0268: this .colorBar = colorBar;
0269: if (colorBar != null) {
0270: colorBar.getAxis().setPlot(this );
0271: colorBar.getAxis().addChangeListener(this );
0272: colorBar.configure(this );
0273: }
0274: this .colorBarLocation = RectangleEdge.LEFT;
0275:
0276: this .toolTipGenerator = new StandardContourToolTipGenerator();
0277:
0278: }
0279:
0280: /**
0281: * Returns the color bar location.
0282: *
0283: * @return The color bar location.
0284: */
0285: public RectangleEdge getColorBarLocation() {
0286: return this .colorBarLocation;
0287: }
0288:
0289: /**
0290: * Sets the color bar location and sends a {@link PlotChangeEvent} to all
0291: * registered listeners.
0292: *
0293: * @param edge the location.
0294: */
0295: public void setColorBarLocation(RectangleEdge edge) {
0296: this .colorBarLocation = edge;
0297: notifyListeners(new PlotChangeEvent(this ));
0298: }
0299:
0300: /**
0301: * Returns the primary dataset for the plot.
0302: *
0303: * @return The primary dataset (possibly <code>null</code>).
0304: */
0305: public ContourDataset getDataset() {
0306: return this .dataset;
0307: }
0308:
0309: /**
0310: * Sets the dataset for the plot, replacing the existing dataset if there
0311: * is one.
0312: *
0313: * @param dataset the dataset (<code>null</code> permitted).
0314: */
0315: public void setDataset(ContourDataset dataset) {
0316:
0317: // if there is an existing dataset, remove the plot from the list of
0318: // change listeners...
0319: ContourDataset existing = this .dataset;
0320: if (existing != null) {
0321: existing.removeChangeListener(this );
0322: }
0323:
0324: // set the new dataset, and register the chart as a change listener...
0325: this .dataset = dataset;
0326: if (dataset != null) {
0327: setDatasetGroup(dataset.getGroup());
0328: dataset.addChangeListener(this );
0329: }
0330:
0331: // send a dataset change event to self...
0332: DatasetChangeEvent event = new DatasetChangeEvent(this , dataset);
0333: datasetChanged(event);
0334:
0335: }
0336:
0337: /**
0338: * Returns the domain axis for the plot.
0339: *
0340: * @return The domain axis.
0341: */
0342: public ValueAxis getDomainAxis() {
0343:
0344: ValueAxis result = this .domainAxis;
0345:
0346: return result;
0347:
0348: }
0349:
0350: /**
0351: * Sets the domain axis for the plot (this must be compatible with the plot
0352: * type or an exception is thrown).
0353: *
0354: * @param axis The new axis.
0355: */
0356: public void setDomainAxis(ValueAxis axis) {
0357:
0358: if (isCompatibleDomainAxis(axis)) {
0359:
0360: if (axis != null) {
0361: axis.setPlot(this );
0362: axis.addChangeListener(this );
0363: }
0364:
0365: // plot is likely registered as a listener with the existing axis...
0366: if (this .domainAxis != null) {
0367: this .domainAxis.removeChangeListener(this );
0368: }
0369:
0370: this .domainAxis = axis;
0371: notifyListeners(new PlotChangeEvent(this ));
0372:
0373: }
0374:
0375: }
0376:
0377: /**
0378: * Returns the range axis for the plot.
0379: *
0380: * @return The range axis.
0381: */
0382: public ValueAxis getRangeAxis() {
0383:
0384: ValueAxis result = this .rangeAxis;
0385:
0386: return result;
0387:
0388: }
0389:
0390: /**
0391: * Sets the range axis for the plot.
0392: * <P>
0393: * An exception is thrown if the new axis and the plot are not mutually
0394: * compatible.
0395: *
0396: * @param axis The new axis (null permitted).
0397: */
0398: public void setRangeAxis(ValueAxis axis) {
0399:
0400: if (axis != null) {
0401: axis.setPlot(this );
0402: axis.addChangeListener(this );
0403: }
0404:
0405: // plot is likely registered as a listener with the existing axis...
0406: if (this .rangeAxis != null) {
0407: this .rangeAxis.removeChangeListener(this );
0408: }
0409:
0410: this .rangeAxis = axis;
0411: notifyListeners(new PlotChangeEvent(this ));
0412:
0413: }
0414:
0415: /**
0416: * Sets the colorbar for the plot.
0417: *
0418: * @param axis The new axis (null permitted).
0419: */
0420: public void setColorBarAxis(ColorBar axis) {
0421:
0422: this .colorBar = axis;
0423: notifyListeners(new PlotChangeEvent(this ));
0424:
0425: }
0426:
0427: /**
0428: * Returns the data area ratio.
0429: *
0430: * @return The ratio.
0431: */
0432: public double getDataAreaRatio() {
0433: return this .dataAreaRatio;
0434: }
0435:
0436: /**
0437: * Sets the data area ratio.
0438: *
0439: * @param ratio the ratio.
0440: */
0441: public void setDataAreaRatio(double ratio) {
0442: this .dataAreaRatio = ratio;
0443: }
0444:
0445: /**
0446: * Adds a marker for the domain axis.
0447: * <P>
0448: * Typically a marker will be drawn by the renderer as a line perpendicular
0449: * to the range axis, however this is entirely up to the renderer.
0450: *
0451: * @param marker the marker.
0452: */
0453: public void addDomainMarker(Marker marker) {
0454:
0455: if (this .domainMarkers == null) {
0456: this .domainMarkers = new java.util.ArrayList();
0457: }
0458: this .domainMarkers.add(marker);
0459: notifyListeners(new PlotChangeEvent(this ));
0460:
0461: }
0462:
0463: /**
0464: * Clears all the domain markers.
0465: */
0466: public void clearDomainMarkers() {
0467: if (this .domainMarkers != null) {
0468: this .domainMarkers.clear();
0469: notifyListeners(new PlotChangeEvent(this ));
0470: }
0471: }
0472:
0473: /**
0474: * Adds a marker for the range axis.
0475: * <P>
0476: * Typically a marker will be drawn by the renderer as a line perpendicular
0477: * to the range axis, however this is entirely up to the renderer.
0478: *
0479: * @param marker The marker.
0480: */
0481: public void addRangeMarker(Marker marker) {
0482:
0483: if (this .rangeMarkers == null) {
0484: this .rangeMarkers = new java.util.ArrayList();
0485: }
0486: this .rangeMarkers.add(marker);
0487: notifyListeners(new PlotChangeEvent(this ));
0488:
0489: }
0490:
0491: /**
0492: * Clears all the range markers.
0493: */
0494: public void clearRangeMarkers() {
0495: if (this .rangeMarkers != null) {
0496: this .rangeMarkers.clear();
0497: notifyListeners(new PlotChangeEvent(this ));
0498: }
0499: }
0500:
0501: /**
0502: * Adds an annotation to the plot.
0503: *
0504: * @param annotation the annotation.
0505: */
0506: public void addAnnotation(XYAnnotation annotation) {
0507:
0508: if (this .annotations == null) {
0509: this .annotations = new java.util.ArrayList();
0510: }
0511: this .annotations.add(annotation);
0512: notifyListeners(new PlotChangeEvent(this ));
0513:
0514: }
0515:
0516: /**
0517: * Clears all the annotations.
0518: */
0519: public void clearAnnotations() {
0520: if (this .annotations != null) {
0521: this .annotations.clear();
0522: notifyListeners(new PlotChangeEvent(this ));
0523: }
0524: }
0525:
0526: /**
0527: * Checks the compatibility of a domain axis, returning true if the axis is
0528: * compatible with the plot, and false otherwise.
0529: *
0530: * @param axis The proposed axis.
0531: *
0532: * @return <code>true</code> if the axis is compatible with the plot.
0533: */
0534: public boolean isCompatibleDomainAxis(ValueAxis axis) {
0535:
0536: return true;
0537:
0538: }
0539:
0540: /**
0541: * Draws the plot on a Java 2D graphics device (such as the screen or a
0542: * printer).
0543: * <P>
0544: * The optional <code>info</code> argument collects information about the
0545: * rendering of the plot (dimensions, tooltip information etc). Just pass
0546: * in <code>null</code> if you do not need this information.
0547: *
0548: * @param g2 the graphics device.
0549: * @param area the area within which the plot (including axis labels)
0550: * should be drawn.
0551: * @param anchor the anchor point (<code>null</code> permitted).
0552: * @param parentState the state from the parent plot, if there is one.
0553: * @param info collects chart drawing information (<code>null</code>
0554: * permitted).
0555: */
0556: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
0557: PlotState parentState, PlotRenderingInfo info) {
0558:
0559: // if the plot area is too small, just return...
0560: boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW);
0561: boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW);
0562: if (b1 || b2) {
0563: return;
0564: }
0565:
0566: // record the plot area...
0567: if (info != null) {
0568: info.setPlotArea(area);
0569: }
0570:
0571: // adjust the drawing area for plot insets (if any)...
0572: RectangleInsets insets = getInsets();
0573: insets.trim(area);
0574:
0575: AxisSpace space = new AxisSpace();
0576:
0577: space = this .domainAxis.reserveSpace(g2, this , area,
0578: RectangleEdge.BOTTOM, space);
0579: space = this .rangeAxis.reserveSpace(g2, this , area,
0580: RectangleEdge.LEFT, space);
0581:
0582: Rectangle2D estimatedDataArea = space.shrink(area, null);
0583:
0584: AxisSpace space2 = new AxisSpace();
0585: space2 = this .colorBar.reserveSpace(g2, this , area,
0586: estimatedDataArea, this .colorBarLocation, space2);
0587: Rectangle2D adjustedPlotArea = space2.shrink(area, null);
0588:
0589: Rectangle2D dataArea = space.shrink(adjustedPlotArea, null);
0590:
0591: Rectangle2D colorBarArea = space2.reserved(area,
0592: this .colorBarLocation);
0593:
0594: // additional dataArea modifications
0595: if (getDataAreaRatio() != 0.0) { //check whether modification is
0596: double ratio = getDataAreaRatio();
0597: Rectangle2D tmpDataArea = (Rectangle2D) dataArea.clone();
0598: double h = tmpDataArea.getHeight();
0599: double w = tmpDataArea.getWidth();
0600:
0601: if (ratio > 0) { // ratio represents pixels
0602: if (w * ratio <= h) {
0603: h = ratio * w;
0604: } else {
0605: w = h / ratio;
0606: }
0607: } else { // ratio represents axis units
0608: ratio *= -1.0;
0609: double xLength = getDomainAxis().getRange().getLength();
0610: double yLength = getRangeAxis().getRange().getLength();
0611: double unitRatio = yLength / xLength;
0612:
0613: ratio = unitRatio * ratio;
0614:
0615: if (w * ratio <= h) {
0616: h = ratio * w;
0617: } else {
0618: w = h / ratio;
0619: }
0620: }
0621:
0622: dataArea.setRect(tmpDataArea.getX()
0623: + tmpDataArea.getWidth() / 2 - w / 2, tmpDataArea
0624: .getY(), w, h);
0625: }
0626:
0627: if (info != null) {
0628: info.setDataArea(dataArea);
0629: }
0630:
0631: CrosshairState crosshairState = new CrosshairState();
0632: crosshairState.setCrosshairDistance(Double.POSITIVE_INFINITY);
0633:
0634: // draw the plot background...
0635: drawBackground(g2, dataArea);
0636:
0637: double cursor = dataArea.getMaxY();
0638: if (this .domainAxis != null) {
0639: this .domainAxis.draw(g2, cursor, adjustedPlotArea,
0640: dataArea, RectangleEdge.BOTTOM, info);
0641: }
0642:
0643: if (this .rangeAxis != null) {
0644: cursor = dataArea.getMinX();
0645: this .rangeAxis.draw(g2, cursor, adjustedPlotArea, dataArea,
0646: RectangleEdge.LEFT, info);
0647: }
0648:
0649: if (this .colorBar != null) {
0650: cursor = 0.0;
0651: cursor = this .colorBar.draw(g2, cursor, adjustedPlotArea,
0652: dataArea, colorBarArea, this .colorBarLocation);
0653: }
0654: Shape originalClip = g2.getClip();
0655: Composite originalComposite = g2.getComposite();
0656:
0657: g2.clip(dataArea);
0658: g2.setComposite(AlphaComposite.getInstance(
0659: AlphaComposite.SRC_OVER, getForegroundAlpha()));
0660: render(g2, dataArea, info, crosshairState);
0661:
0662: if (this .domainMarkers != null) {
0663: Iterator iterator = this .domainMarkers.iterator();
0664: while (iterator.hasNext()) {
0665: Marker marker = (Marker) iterator.next();
0666: drawDomainMarker(g2, this , getDomainAxis(), marker,
0667: dataArea);
0668: }
0669: }
0670:
0671: if (this .rangeMarkers != null) {
0672: Iterator iterator = this .rangeMarkers.iterator();
0673: while (iterator.hasNext()) {
0674: Marker marker = (Marker) iterator.next();
0675: drawRangeMarker(g2, this , getRangeAxis(), marker,
0676: dataArea);
0677: }
0678: }
0679:
0680: // TO DO: these annotations only work with XYPlot, see if it is possible to
0681: // make ContourPlot a subclass of XYPlot (DG);
0682:
0683: // // draw the annotations...
0684: // if (this.annotations != null) {
0685: // Iterator iterator = this.annotations.iterator();
0686: // while (iterator.hasNext()) {
0687: // Annotation annotation = (Annotation) iterator.next();
0688: // if (annotation instanceof XYAnnotation) {
0689: // XYAnnotation xya = (XYAnnotation) annotation;
0690: // // get the annotation to draw itself...
0691: // xya.draw(g2, this, dataArea, getDomainAxis(),
0692: // getRangeAxis());
0693: // }
0694: // }
0695: // }
0696:
0697: g2.setClip(originalClip);
0698: g2.setComposite(originalComposite);
0699: drawOutline(g2, dataArea);
0700:
0701: }
0702:
0703: /**
0704: * Draws a representation of the data within the dataArea region, using the
0705: * current renderer.
0706: * <P>
0707: * The <code>info</code> and <code>crosshairState</code> arguments may be
0708: * <code>null</code>.
0709: *
0710: * @param g2 the graphics device.
0711: * @param dataArea the region in which the data is to be drawn.
0712: * @param info an optional object for collection dimension information.
0713: * @param crosshairState an optional object for collecting crosshair info.
0714: */
0715: public void render(Graphics2D g2, Rectangle2D dataArea,
0716: PlotRenderingInfo info, CrosshairState crosshairState) {
0717:
0718: // now get the data and plot it (the visual representation will depend
0719: // on the renderer that has been set)...
0720: ContourDataset data = getDataset();
0721: if (data != null) {
0722:
0723: ColorBar zAxis = getColorBar();
0724:
0725: if (this .clipPath != null) {
0726: GeneralPath clipper = getClipPath().draw(g2, dataArea,
0727: this .domainAxis, this .rangeAxis);
0728: if (this .clipPath.isClip()) {
0729: g2.clip(clipper);
0730: }
0731: }
0732:
0733: if (this .renderAsPoints) {
0734: pointRenderer(g2, dataArea, info, this ,
0735: this .domainAxis, this .rangeAxis, zAxis, data,
0736: crosshairState);
0737: } else {
0738: contourRenderer(g2, dataArea, info, this ,
0739: this .domainAxis, this .rangeAxis, zAxis, data,
0740: crosshairState);
0741: }
0742:
0743: // draw vertical crosshair if required...
0744: setDomainCrosshairValue(crosshairState.getCrosshairX(),
0745: false);
0746: if (isDomainCrosshairVisible()) {
0747: drawVerticalLine(g2, dataArea,
0748: getDomainCrosshairValue(),
0749: getDomainCrosshairStroke(),
0750: getDomainCrosshairPaint());
0751: }
0752:
0753: // draw horizontal crosshair if required...
0754: setRangeCrosshairValue(crosshairState.getCrosshairY(),
0755: false);
0756: if (isRangeCrosshairVisible()) {
0757: drawHorizontalLine(g2, dataArea,
0758: getRangeCrosshairValue(),
0759: getRangeCrosshairStroke(),
0760: getRangeCrosshairPaint());
0761: }
0762:
0763: } else if (this .clipPath != null) {
0764: getClipPath().draw(g2, dataArea, this .domainAxis,
0765: this .rangeAxis);
0766: }
0767:
0768: }
0769:
0770: /**
0771: * Fills the plot.
0772: *
0773: * @param g2 the graphics device.
0774: * @param dataArea the area within which the data is being drawn.
0775: * @param info collects information about the drawing.
0776: * @param plot the plot (can be used to obtain standard color
0777: * information etc).
0778: * @param horizontalAxis the domain (horizontal) axis.
0779: * @param verticalAxis the range (vertical) axis.
0780: * @param colorBar the color bar axis.
0781: * @param data the dataset.
0782: * @param crosshairState information about crosshairs on a plot.
0783: */
0784: public void contourRenderer(Graphics2D g2, Rectangle2D dataArea,
0785: PlotRenderingInfo info, ContourPlot plot,
0786: ValueAxis horizontalAxis, ValueAxis verticalAxis,
0787: ColorBar colorBar, ContourDataset data,
0788: CrosshairState crosshairState) {
0789:
0790: // setup for collecting optional entity info...
0791: Rectangle2D.Double entityArea = null;
0792: EntityCollection entities = null;
0793: if (info != null) {
0794: entities = info.getOwner().getEntityCollection();
0795: }
0796:
0797: Rectangle2D.Double rect = null;
0798: rect = new Rectangle2D.Double();
0799:
0800: //turn off anti-aliasing when filling rectangles
0801: Object antiAlias = g2
0802: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
0803: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
0804: RenderingHints.VALUE_ANTIALIAS_OFF);
0805:
0806: // get the data points
0807: Number[] xNumber = data.getXValues();
0808: Number[] yNumber = data.getYValues();
0809: Number[] zNumber = data.getZValues();
0810:
0811: double[] x = new double[xNumber.length];
0812: double[] y = new double[yNumber.length];
0813:
0814: for (int i = 0; i < x.length; i++) {
0815: x[i] = xNumber[i].doubleValue();
0816: y[i] = yNumber[i].doubleValue();
0817: }
0818:
0819: int[] xIndex = data.indexX();
0820: int[] indexX = data.getXIndices();
0821: boolean vertInverted = ((NumberAxis) verticalAxis).isInverted();
0822: boolean horizInverted = false;
0823: if (horizontalAxis instanceof NumberAxis) {
0824: horizInverted = ((NumberAxis) horizontalAxis).isInverted();
0825: }
0826: double transX = 0.0;
0827: double transXm1 = 0.0;
0828: double transXp1 = 0.0;
0829: double transDXm1 = 0.0;
0830: double transDXp1 = 0.0;
0831: double transDX = 0.0;
0832: double transY = 0.0;
0833: double transYm1 = 0.0;
0834: double transYp1 = 0.0;
0835: double transDYm1 = 0.0;
0836: double transDYp1 = 0.0;
0837: double transDY = 0.0;
0838: int iMax = xIndex[xIndex.length - 1];
0839: for (int k = 0; k < x.length; k++) {
0840: int i = xIndex[k];
0841: if (indexX[i] == k) { // this is a new column
0842: if (i == 0) {
0843: transX = horizontalAxis.valueToJava2D(x[k],
0844: dataArea, RectangleEdge.BOTTOM);
0845: transXm1 = transX;
0846: transXp1 = horizontalAxis.valueToJava2D(
0847: x[indexX[i + 1]], dataArea,
0848: RectangleEdge.BOTTOM);
0849: transDXm1 = Math.abs(0.5 * (transX - transXm1));
0850: transDXp1 = Math.abs(0.5 * (transX - transXp1));
0851: } else if (i == iMax) {
0852: transX = horizontalAxis.valueToJava2D(x[k],
0853: dataArea, RectangleEdge.BOTTOM);
0854: transXm1 = horizontalAxis.valueToJava2D(
0855: x[indexX[i - 1]], dataArea,
0856: RectangleEdge.BOTTOM);
0857: transXp1 = transX;
0858: transDXm1 = Math.abs(0.5 * (transX - transXm1));
0859: transDXp1 = Math.abs(0.5 * (transX - transXp1));
0860: } else {
0861: transX = horizontalAxis.valueToJava2D(x[k],
0862: dataArea, RectangleEdge.BOTTOM);
0863: transXp1 = horizontalAxis.valueToJava2D(
0864: x[indexX[i + 1]], dataArea,
0865: RectangleEdge.BOTTOM);
0866: transDXm1 = transDXp1;
0867: transDXp1 = Math.abs(0.5 * (transX - transXp1));
0868: }
0869:
0870: if (horizInverted) {
0871: transX -= transDXp1;
0872: } else {
0873: transX -= transDXm1;
0874: }
0875:
0876: transDX = transDXm1 + transDXp1;
0877:
0878: transY = verticalAxis.valueToJava2D(y[k], dataArea,
0879: RectangleEdge.LEFT);
0880: transYm1 = transY;
0881: if (k + 1 == y.length) {
0882: continue;
0883: }
0884: transYp1 = verticalAxis.valueToJava2D(y[k + 1],
0885: dataArea, RectangleEdge.LEFT);
0886: transDYm1 = Math.abs(0.5 * (transY - transYm1));
0887: transDYp1 = Math.abs(0.5 * (transY - transYp1));
0888: } else if ((i < indexX.length - 1 && indexX[i + 1] - 1 == k)
0889: || k == x.length - 1) {
0890: // end of column
0891: transY = verticalAxis.valueToJava2D(y[k], dataArea,
0892: RectangleEdge.LEFT);
0893: transYm1 = verticalAxis.valueToJava2D(y[k - 1],
0894: dataArea, RectangleEdge.LEFT);
0895: transYp1 = transY;
0896: transDYm1 = Math.abs(0.5 * (transY - transYm1));
0897: transDYp1 = Math.abs(0.5 * (transY - transYp1));
0898: } else {
0899: transY = verticalAxis.valueToJava2D(y[k], dataArea,
0900: RectangleEdge.LEFT);
0901: transYp1 = verticalAxis.valueToJava2D(y[k + 1],
0902: dataArea, RectangleEdge.LEFT);
0903: transDYm1 = transDYp1;
0904: transDYp1 = Math.abs(0.5 * (transY - transYp1));
0905: }
0906: if (vertInverted) {
0907: transY -= transDYm1;
0908: } else {
0909: transY -= transDYp1;
0910: }
0911:
0912: transDY = transDYm1 + transDYp1;
0913:
0914: rect.setRect(transX, transY, transDX, transDY);
0915: if (zNumber[k] != null) {
0916: g2
0917: .setPaint(colorBar.getPaint(zNumber[k]
0918: .doubleValue()));
0919: g2.fill(rect);
0920: } else if (this .missingPaint != null) {
0921: g2.setPaint(this .missingPaint);
0922: g2.fill(rect);
0923: }
0924:
0925: entityArea = rect;
0926:
0927: // add an entity for the item...
0928: if (entities != null) {
0929: String tip = "";
0930: if (getToolTipGenerator() != null) {
0931: tip = this .toolTipGenerator
0932: .generateToolTip(data, k);
0933: }
0934: // Shape s = g2.getClip();
0935: // if (s.contains(rect) || s.intersects(rect)) {
0936: String url = null;
0937: // if (getURLGenerator() != null) { //dmo: look at this later
0938: // url = getURLGenerator().generateURL(data, series, item);
0939: // }
0940: // Unlike XYItemRenderer, we need to clone entityArea since it
0941: // reused.
0942: ContourEntity entity = new ContourEntity(
0943: (Rectangle2D.Double) entityArea.clone(), tip,
0944: url);
0945: entity.setIndex(k);
0946: entities.add(entity);
0947: // }
0948: }
0949:
0950: // do we need to update the crosshair values?
0951: if (plot.isDomainCrosshairLockedOnData()) {
0952: if (plot.isRangeCrosshairLockedOnData()) {
0953: // both axes
0954: crosshairState.updateCrosshairPoint(x[k], y[k],
0955: transX, transY, PlotOrientation.VERTICAL);
0956: } else {
0957: // just the horizontal axis...
0958: crosshairState.updateCrosshairX(transX);
0959: }
0960: } else {
0961: if (plot.isRangeCrosshairLockedOnData()) {
0962: // just the vertical axis...
0963: crosshairState.updateCrosshairY(transY);
0964: }
0965: }
0966: }
0967:
0968: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias);
0969:
0970: return;
0971:
0972: }
0973:
0974: /**
0975: * Draws the visual representation of a single data item.
0976: *
0977: * @param g2 the graphics device.
0978: * @param dataArea the area within which the data is being drawn.
0979: * @param info collects information about the drawing.
0980: * @param plot the plot (can be used to obtain standard color
0981: * information etc).
0982: * @param domainAxis the domain (horizontal) axis.
0983: * @param rangeAxis the range (vertical) axis.
0984: * @param colorBar the color bar axis.
0985: * @param data the dataset.
0986: * @param crosshairState information about crosshairs on a plot.
0987: */
0988: public void pointRenderer(Graphics2D g2, Rectangle2D dataArea,
0989: PlotRenderingInfo info, ContourPlot plot,
0990: ValueAxis domainAxis, ValueAxis rangeAxis,
0991: ColorBar colorBar, ContourDataset data,
0992: CrosshairState crosshairState) {
0993:
0994: // setup for collecting optional entity info...
0995: RectangularShape entityArea = null;
0996: EntityCollection entities = null;
0997: if (info != null) {
0998: entities = info.getOwner().getEntityCollection();
0999: }
1000:
1001: // Rectangle2D.Double rect = null;
1002: // rect = new Rectangle2D.Double();
1003: RectangularShape rect = new Ellipse2D.Double();
1004:
1005: //turn off anti-aliasing when filling rectangles
1006: Object antiAlias = g2
1007: .getRenderingHint(RenderingHints.KEY_ANTIALIASING);
1008: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1009: RenderingHints.VALUE_ANTIALIAS_OFF);
1010:
1011: // if (tooltips!=null) tooltips.clearToolTips(); // reset collection
1012: // get the data points
1013: Number[] xNumber = data.getXValues();
1014: Number[] yNumber = data.getYValues();
1015: Number[] zNumber = data.getZValues();
1016:
1017: double[] x = new double[xNumber.length];
1018: double[] y = new double[yNumber.length];
1019:
1020: for (int i = 0; i < x.length; i++) {
1021: x[i] = xNumber[i].doubleValue();
1022: y[i] = yNumber[i].doubleValue();
1023: }
1024:
1025: double transX = 0.0;
1026: double transDX = 0.0;
1027: double transY = 0.0;
1028: double transDY = 0.0;
1029: double size = dataArea.getWidth() * this .ptSizePct;
1030: for (int k = 0; k < x.length; k++) {
1031:
1032: transX = domainAxis.valueToJava2D(x[k], dataArea,
1033: RectangleEdge.BOTTOM)
1034: - 0.5 * size;
1035: transY = rangeAxis.valueToJava2D(y[k], dataArea,
1036: RectangleEdge.LEFT)
1037: - 0.5 * size;
1038: transDX = size;
1039: transDY = size;
1040:
1041: rect.setFrame(transX, transY, transDX, transDY);
1042:
1043: if (zNumber[k] != null) {
1044: g2
1045: .setPaint(colorBar.getPaint(zNumber[k]
1046: .doubleValue()));
1047: g2.fill(rect);
1048: } else if (this .missingPaint != null) {
1049: g2.setPaint(this .missingPaint);
1050: g2.fill(rect);
1051: }
1052:
1053: entityArea = rect;
1054:
1055: // add an entity for the item...
1056: if (entities != null) {
1057: String tip = null;
1058: if (getToolTipGenerator() != null) {
1059: tip = this .toolTipGenerator
1060: .generateToolTip(data, k);
1061: }
1062: String url = null;
1063: // if (getURLGenerator() != null) { //dmo: look at this later
1064: // url = getURLGenerator().generateURL(data, series, item);
1065: // }
1066: // Unlike XYItemRenderer, we need to clone entityArea since it
1067: // reused.
1068: ContourEntity entity = new ContourEntity(
1069: (RectangularShape) entityArea.clone(), tip, url);
1070: entity.setIndex(k);
1071: entities.add(entity);
1072: }
1073:
1074: // do we need to update the crosshair values?
1075: if (plot.isDomainCrosshairLockedOnData()) {
1076: if (plot.isRangeCrosshairLockedOnData()) {
1077: // both axes
1078: crosshairState.updateCrosshairPoint(x[k], y[k],
1079: transX, transY, PlotOrientation.VERTICAL);
1080: } else {
1081: // just the horizontal axis...
1082: crosshairState.updateCrosshairX(transX);
1083: }
1084: } else {
1085: if (plot.isRangeCrosshairLockedOnData()) {
1086: // just the vertical axis...
1087: crosshairState.updateCrosshairY(transY);
1088: }
1089: }
1090: }
1091:
1092: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias);
1093:
1094: return;
1095:
1096: }
1097:
1098: /**
1099: * Utility method for drawing a crosshair on the chart (if required).
1100: *
1101: * @param g2 The graphics device.
1102: * @param dataArea The data area.
1103: * @param value The coordinate, where to draw the line.
1104: * @param stroke The stroke to use.
1105: * @param paint The paint to use.
1106: */
1107: protected void drawVerticalLine(Graphics2D g2,
1108: Rectangle2D dataArea, double value, Stroke stroke,
1109: Paint paint) {
1110:
1111: double xx = getDomainAxis().valueToJava2D(value, dataArea,
1112: RectangleEdge.BOTTOM);
1113: Line2D line = new Line2D.Double(xx, dataArea.getMinY(), xx,
1114: dataArea.getMaxY());
1115: g2.setStroke(stroke);
1116: g2.setPaint(paint);
1117: g2.draw(line);
1118:
1119: }
1120:
1121: /**
1122: * Utility method for drawing a crosshair on the chart (if required).
1123: *
1124: * @param g2 The graphics device.
1125: * @param dataArea The data area.
1126: * @param value The coordinate, where to draw the line.
1127: * @param stroke The stroke to use.
1128: * @param paint The paint to use.
1129: */
1130: protected void drawHorizontalLine(Graphics2D g2,
1131: Rectangle2D dataArea, double value, Stroke stroke,
1132: Paint paint) {
1133:
1134: double yy = getRangeAxis().valueToJava2D(value, dataArea,
1135: RectangleEdge.LEFT);
1136: Line2D line = new Line2D.Double(dataArea.getMinX(), yy,
1137: dataArea.getMaxX(), yy);
1138: g2.setStroke(stroke);
1139: g2.setPaint(paint);
1140: g2.draw(line);
1141:
1142: }
1143:
1144: /**
1145: * Handles a 'click' on the plot by updating the anchor values...
1146: *
1147: * @param x x-coordinate, where the click occured.
1148: * @param y y-coordinate, where the click occured.
1149: * @param info An object for collection dimension information.
1150: */
1151: public void handleClick(int x, int y, PlotRenderingInfo info) {
1152:
1153: /* // set the anchor value for the horizontal axis...
1154: ValueAxis hva = getDomainAxis();
1155: if (hva != null) {
1156: double hvalue = hva.translateJava2DtoValue(
1157: (float) x, info.getDataArea()
1158: );
1159:
1160: hva.setAnchorValue(hvalue);
1161: setDomainCrosshairValue(hvalue);
1162: }
1163:
1164: // set the anchor value for the vertical axis...
1165: ValueAxis vva = getRangeAxis();
1166: if (vva != null) {
1167: double vvalue = vva.translateJava2DtoValue(
1168: (float) y, info.getDataArea()
1169: );
1170: vva.setAnchorValue(vvalue);
1171: setRangeCrosshairValue(vvalue);
1172: }
1173: */
1174: }
1175:
1176: /**
1177: * Zooms the axis ranges by the specified percentage about the anchor point.
1178: *
1179: * @param percent The amount of the zoom.
1180: */
1181: public void zoom(double percent) {
1182:
1183: if (percent > 0) {
1184: // double range = this.domainAxis.getRange().getLength();
1185: // double scaledRange = range * percent;
1186: // domainAxis.setAnchoredRange(scaledRange);
1187:
1188: // range = this.rangeAxis.getRange().getLength();
1189: // scaledRange = range * percent;
1190: // rangeAxis.setAnchoredRange(scaledRange);
1191: } else {
1192: getRangeAxis().setAutoRange(true);
1193: getDomainAxis().setAutoRange(true);
1194: }
1195:
1196: }
1197:
1198: /**
1199: * Returns the plot type as a string.
1200: *
1201: * @return A short string describing the type of plot.
1202: */
1203: public String getPlotType() {
1204: return localizationResources.getString("Contour_Plot");
1205: }
1206:
1207: /**
1208: * Returns the range for an axis.
1209: *
1210: * @param axis the axis.
1211: *
1212: * @return The range for an axis.
1213: */
1214: public Range getDataRange(ValueAxis axis) {
1215:
1216: if (this .dataset == null) {
1217: return null;
1218: }
1219:
1220: Range result = null;
1221:
1222: if (axis == getDomainAxis()) {
1223: result = DatasetUtilities.findDomainBounds(this .dataset);
1224: } else if (axis == getRangeAxis()) {
1225: result = DatasetUtilities.findRangeBounds(this .dataset);
1226: }
1227:
1228: return result;
1229:
1230: }
1231:
1232: /**
1233: * Returns the range for the Contours.
1234: *
1235: * @return The range for the Contours (z-axis).
1236: */
1237: public Range getContourDataRange() {
1238:
1239: Range result = null;
1240:
1241: ContourDataset data = getDataset();
1242:
1243: if (data != null) {
1244: Range h = getDomainAxis().getRange();
1245: Range v = getRangeAxis().getRange();
1246: result = this .visibleRange(data, h, v);
1247: }
1248:
1249: return result;
1250: }
1251:
1252: /**
1253: * Notifies all registered listeners of a property change.
1254: * <P>
1255: * One source of property change events is the plot's renderer.
1256: *
1257: * @param event Information about the property change.
1258: */
1259: public void propertyChange(PropertyChangeEvent event) {
1260: notifyListeners(new PlotChangeEvent(this ));
1261: }
1262:
1263: /**
1264: * Receives notification of a change to the plot's dataset.
1265: * <P>
1266: * The chart reacts by passing on a chart change event to all registered
1267: * listeners.
1268: *
1269: * @param event Information about the event (not used here).
1270: */
1271: public void datasetChanged(DatasetChangeEvent event) {
1272: if (this .domainAxis != null) {
1273: this .domainAxis.configure();
1274: }
1275: if (this .rangeAxis != null) {
1276: this .rangeAxis.configure();
1277: }
1278: if (this .colorBar != null) {
1279: this .colorBar.configure(this );
1280: }
1281: super .datasetChanged(event);
1282: }
1283:
1284: /**
1285: * Returns the colorbar.
1286: *
1287: * @return The colorbar.
1288: */
1289: public ColorBar getColorBar() {
1290: return this .colorBar;
1291: }
1292:
1293: /**
1294: * Returns a flag indicating whether or not the domain crosshair is visible.
1295: *
1296: * @return The flag.
1297: */
1298: public boolean isDomainCrosshairVisible() {
1299: return this .domainCrosshairVisible;
1300: }
1301:
1302: /**
1303: * Sets the flag indicating whether or not the domain crosshair is visible.
1304: *
1305: * @param flag the new value of the flag.
1306: */
1307: public void setDomainCrosshairVisible(boolean flag) {
1308:
1309: if (this .domainCrosshairVisible != flag) {
1310: this .domainCrosshairVisible = flag;
1311: notifyListeners(new PlotChangeEvent(this ));
1312: }
1313:
1314: }
1315:
1316: /**
1317: * Returns a flag indicating whether or not the crosshair should "lock-on"
1318: * to actual data values.
1319: *
1320: * @return The flag.
1321: */
1322: public boolean isDomainCrosshairLockedOnData() {
1323: return this .domainCrosshairLockedOnData;
1324: }
1325:
1326: /**
1327: * Sets the flag indicating whether or not the domain crosshair should
1328: * "lock-on" to actual data values.
1329: *
1330: * @param flag the flag.
1331: */
1332: public void setDomainCrosshairLockedOnData(boolean flag) {
1333: if (this .domainCrosshairLockedOnData != flag) {
1334: this .domainCrosshairLockedOnData = flag;
1335: notifyListeners(new PlotChangeEvent(this ));
1336: }
1337: }
1338:
1339: /**
1340: * Returns the domain crosshair value.
1341: *
1342: * @return The value.
1343: */
1344: public double getDomainCrosshairValue() {
1345: return this .domainCrosshairValue;
1346: }
1347:
1348: /**
1349: * Sets the domain crosshair value.
1350: * <P>
1351: * Registered listeners are notified that the plot has been modified, but
1352: * only if the crosshair is visible.
1353: *
1354: * @param value the new value.
1355: */
1356: public void setDomainCrosshairValue(double value) {
1357: setDomainCrosshairValue(value, true);
1358: }
1359:
1360: /**
1361: * Sets the domain crosshair value.
1362: * <P>
1363: * Registered listeners are notified that the axis has been modified, but
1364: * only if the crosshair is visible.
1365: *
1366: * @param value the new value.
1367: * @param notify a flag that controls whether or not listeners are
1368: * notified.
1369: */
1370: public void setDomainCrosshairValue(double value, boolean notify) {
1371: this .domainCrosshairValue = value;
1372: if (isDomainCrosshairVisible() && notify) {
1373: notifyListeners(new PlotChangeEvent(this ));
1374: }
1375: }
1376:
1377: /**
1378: * Returns the Stroke used to draw the crosshair (if visible).
1379: *
1380: * @return The crosshair stroke.
1381: */
1382: public Stroke getDomainCrosshairStroke() {
1383: return this .domainCrosshairStroke;
1384: }
1385:
1386: /**
1387: * Sets the Stroke used to draw the crosshairs (if visible) and notifies
1388: * registered listeners that the axis has been modified.
1389: *
1390: * @param stroke the new crosshair stroke.
1391: */
1392: public void setDomainCrosshairStroke(Stroke stroke) {
1393: this .domainCrosshairStroke = stroke;
1394: notifyListeners(new PlotChangeEvent(this ));
1395: }
1396:
1397: /**
1398: * Returns the domain crosshair color.
1399: *
1400: * @return The crosshair color.
1401: */
1402: public Paint getDomainCrosshairPaint() {
1403: return this .domainCrosshairPaint;
1404: }
1405:
1406: /**
1407: * Sets the Paint used to color the crosshairs (if visible) and notifies
1408: * registered listeners that the axis has been modified.
1409: *
1410: * @param paint the new crosshair paint.
1411: */
1412: public void setDomainCrosshairPaint(Paint paint) {
1413: this .domainCrosshairPaint = paint;
1414: notifyListeners(new PlotChangeEvent(this ));
1415: }
1416:
1417: /**
1418: * Returns a flag indicating whether or not the range crosshair is visible.
1419: *
1420: * @return The flag.
1421: */
1422: public boolean isRangeCrosshairVisible() {
1423: return this .rangeCrosshairVisible;
1424: }
1425:
1426: /**
1427: * Sets the flag indicating whether or not the range crosshair is visible.
1428: *
1429: * @param flag the new value of the flag.
1430: */
1431: public void setRangeCrosshairVisible(boolean flag) {
1432: if (this .rangeCrosshairVisible != flag) {
1433: this .rangeCrosshairVisible = flag;
1434: notifyListeners(new PlotChangeEvent(this ));
1435: }
1436: }
1437:
1438: /**
1439: * Returns a flag indicating whether or not the crosshair should "lock-on"
1440: * to actual data values.
1441: *
1442: * @return The flag.
1443: */
1444: public boolean isRangeCrosshairLockedOnData() {
1445: return this .rangeCrosshairLockedOnData;
1446: }
1447:
1448: /**
1449: * Sets the flag indicating whether or not the range crosshair should
1450: * "lock-on" to actual data values.
1451: *
1452: * @param flag the flag.
1453: */
1454: public void setRangeCrosshairLockedOnData(boolean flag) {
1455: if (this .rangeCrosshairLockedOnData != flag) {
1456: this .rangeCrosshairLockedOnData = flag;
1457: notifyListeners(new PlotChangeEvent(this ));
1458: }
1459: }
1460:
1461: /**
1462: * Returns the range crosshair value.
1463: *
1464: * @return The value.
1465: */
1466: public double getRangeCrosshairValue() {
1467: return this .rangeCrosshairValue;
1468: }
1469:
1470: /**
1471: * Sets the domain crosshair value.
1472: * <P>
1473: * Registered listeners are notified that the plot has been modified, but
1474: * only if the crosshair is visible.
1475: *
1476: * @param value the new value.
1477: */
1478: public void setRangeCrosshairValue(double value) {
1479: setRangeCrosshairValue(value, true);
1480: }
1481:
1482: /**
1483: * Sets the range crosshair value.
1484: * <P>
1485: * Registered listeners are notified that the axis has been modified, but
1486: * only if the crosshair is visible.
1487: *
1488: * @param value the new value.
1489: * @param notify a flag that controls whether or not listeners are
1490: * notified.
1491: */
1492: public void setRangeCrosshairValue(double value, boolean notify) {
1493: this .rangeCrosshairValue = value;
1494: if (isRangeCrosshairVisible() && notify) {
1495: notifyListeners(new PlotChangeEvent(this ));
1496: }
1497: }
1498:
1499: /**
1500: * Returns the Stroke used to draw the crosshair (if visible).
1501: *
1502: * @return The crosshair stroke.
1503: */
1504: public Stroke getRangeCrosshairStroke() {
1505: return this .rangeCrosshairStroke;
1506: }
1507:
1508: /**
1509: * Sets the Stroke used to draw the crosshairs (if visible) and notifies
1510: * registered listeners that the axis has been modified.
1511: *
1512: * @param stroke the new crosshair stroke.
1513: */
1514: public void setRangeCrosshairStroke(Stroke stroke) {
1515: this .rangeCrosshairStroke = stroke;
1516: notifyListeners(new PlotChangeEvent(this ));
1517: }
1518:
1519: /**
1520: * Returns the range crosshair color.
1521: *
1522: * @return The crosshair color.
1523: */
1524: public Paint getRangeCrosshairPaint() {
1525: return this .rangeCrosshairPaint;
1526: }
1527:
1528: /**
1529: * Sets the Paint used to color the crosshairs (if visible) and notifies
1530: * registered listeners that the axis has been modified.
1531: *
1532: * @param paint the new crosshair paint.
1533: */
1534: public void setRangeCrosshairPaint(Paint paint) {
1535: this .rangeCrosshairPaint = paint;
1536: notifyListeners(new PlotChangeEvent(this ));
1537: }
1538:
1539: /**
1540: * Returns the tool tip generator.
1541: *
1542: * @return The tool tip generator (possibly null).
1543: */
1544: public ContourToolTipGenerator getToolTipGenerator() {
1545: return this .toolTipGenerator;
1546: }
1547:
1548: /**
1549: * Sets the tool tip generator.
1550: *
1551: * @param generator the tool tip generator (null permitted).
1552: */
1553: public void setToolTipGenerator(ContourToolTipGenerator generator) {
1554: //Object oldValue = this.toolTipGenerator;
1555: this .toolTipGenerator = generator;
1556: }
1557:
1558: /**
1559: * Returns the URL generator for HTML image maps.
1560: *
1561: * @return The URL generator (possibly null).
1562: */
1563: public XYURLGenerator getURLGenerator() {
1564: return this .urlGenerator;
1565: }
1566:
1567: /**
1568: * Sets the URL generator for HTML image maps.
1569: *
1570: * @param urlGenerator the URL generator (null permitted).
1571: */
1572: public void setURLGenerator(XYURLGenerator urlGenerator) {
1573: //Object oldValue = this.urlGenerator;
1574: this .urlGenerator = urlGenerator;
1575: }
1576:
1577: /**
1578: * Draws a vertical line on the chart to represent a 'range marker'.
1579: *
1580: * @param g2 the graphics device.
1581: * @param plot the plot.
1582: * @param domainAxis the domain axis.
1583: * @param marker the marker line.
1584: * @param dataArea the axis data area.
1585: */
1586: public void drawDomainMarker(Graphics2D g2, ContourPlot plot,
1587: ValueAxis domainAxis, Marker marker, Rectangle2D dataArea) {
1588:
1589: if (marker instanceof ValueMarker) {
1590: ValueMarker vm = (ValueMarker) marker;
1591: double value = vm.getValue();
1592: Range range = domainAxis.getRange();
1593: if (!range.contains(value)) {
1594: return;
1595: }
1596:
1597: double x = domainAxis.valueToJava2D(value, dataArea,
1598: RectangleEdge.BOTTOM);
1599: Line2D line = new Line2D.Double(x, dataArea.getMinY(), x,
1600: dataArea.getMaxY());
1601: Paint paint = marker.getOutlinePaint();
1602: Stroke stroke = marker.getOutlineStroke();
1603: g2.setPaint(paint != null ? paint
1604: : Plot.DEFAULT_OUTLINE_PAINT);
1605: g2.setStroke(stroke != null ? stroke
1606: : Plot.DEFAULT_OUTLINE_STROKE);
1607: g2.draw(line);
1608: }
1609:
1610: }
1611:
1612: /**
1613: * Draws a horizontal line across the chart to represent a 'range marker'.
1614: *
1615: * @param g2 the graphics device.
1616: * @param plot the plot.
1617: * @param rangeAxis the range axis.
1618: * @param marker the marker line.
1619: * @param dataArea the axis data area.
1620: */
1621: public void drawRangeMarker(Graphics2D g2, ContourPlot plot,
1622: ValueAxis rangeAxis, Marker marker, Rectangle2D dataArea) {
1623:
1624: if (marker instanceof ValueMarker) {
1625: ValueMarker vm = (ValueMarker) marker;
1626: double value = vm.getValue();
1627: Range range = rangeAxis.getRange();
1628: if (!range.contains(value)) {
1629: return;
1630: }
1631:
1632: double y = rangeAxis.valueToJava2D(value, dataArea,
1633: RectangleEdge.LEFT);
1634: Line2D line = new Line2D.Double(dataArea.getMinX(), y,
1635: dataArea.getMaxX(), y);
1636: Paint paint = marker.getOutlinePaint();
1637: Stroke stroke = marker.getOutlineStroke();
1638: g2.setPaint(paint != null ? paint
1639: : Plot.DEFAULT_OUTLINE_PAINT);
1640: g2.setStroke(stroke != null ? stroke
1641: : Plot.DEFAULT_OUTLINE_STROKE);
1642: g2.draw(line);
1643: }
1644:
1645: }
1646:
1647: /**
1648: * Returns the clipPath.
1649: * @return ClipPath
1650: */
1651: public ClipPath getClipPath() {
1652: return this .clipPath;
1653: }
1654:
1655: /**
1656: * Sets the clipPath.
1657: * @param clipPath The clipPath to set
1658: */
1659: public void setClipPath(ClipPath clipPath) {
1660: this .clipPath = clipPath;
1661: }
1662:
1663: /**
1664: * Returns the ptSizePct.
1665: * @return double
1666: */
1667: public double getPtSizePct() {
1668: return this .ptSizePct;
1669: }
1670:
1671: /**
1672: * Returns the renderAsPoints.
1673: * @return boolean
1674: */
1675: public boolean isRenderAsPoints() {
1676: return this .renderAsPoints;
1677: }
1678:
1679: /**
1680: * Sets the ptSizePct.
1681: * @param ptSizePct The ptSizePct to set
1682: */
1683: public void setPtSizePct(double ptSizePct) {
1684: this .ptSizePct = ptSizePct;
1685: }
1686:
1687: /**
1688: * Sets the renderAsPoints.
1689: * @param renderAsPoints The renderAsPoints to set
1690: */
1691: public void setRenderAsPoints(boolean renderAsPoints) {
1692: this .renderAsPoints = renderAsPoints;
1693: }
1694:
1695: /**
1696: * Receives notification of a change to one of the plot's axes.
1697: *
1698: * @param event information about the event.
1699: */
1700: public void axisChanged(AxisChangeEvent event) {
1701: Object source = event.getSource();
1702: if (source.equals(this .rangeAxis)
1703: || source.equals(this .domainAxis)) {
1704: ColorBar cba = this .colorBar;
1705: if (this .colorBar.getAxis().isAutoRange()) {
1706: cba.getAxis().configure();
1707: }
1708:
1709: }
1710: super .axisChanged(event);
1711: }
1712:
1713: /**
1714: * Returns the visible z-range.
1715: *
1716: * @param data the dataset.
1717: * @param x the x range.
1718: * @param y the y range.
1719: *
1720: * @return The range.
1721: */
1722: public Range visibleRange(ContourDataset data, Range x, Range y) {
1723: Range range = null;
1724: range = data.getZValueRange(x, y);
1725: return range;
1726: }
1727:
1728: /**
1729: * Returns the missingPaint.
1730: * @return Paint
1731: */
1732: public Paint getMissingPaint() {
1733: return this .missingPaint;
1734: }
1735:
1736: /**
1737: * Sets the missingPaint.
1738: *
1739: * @param paint the missingPaint to set.
1740: */
1741: public void setMissingPaint(Paint paint) {
1742: this .missingPaint = paint;
1743: }
1744:
1745: /**
1746: * Multiplies the range on the domain axis/axes by the specified factor
1747: * (to be implemented).
1748: *
1749: * @param x the x-coordinate (in Java2D space).
1750: * @param y the y-coordinate (in Java2D space).
1751: * @param factor the zoom factor.
1752: */
1753: public void zoomDomainAxes(double x, double y, double factor) {
1754: // TODO: to be implemented
1755: }
1756:
1757: /**
1758: * Zooms the domain axes (not yet implemented).
1759: *
1760: * @param x the x-coordinate (in Java2D space).
1761: * @param y the y-coordinate (in Java2D space).
1762: * @param lowerPercent the new lower bound.
1763: * @param upperPercent the new upper bound.
1764: */
1765: public void zoomDomainAxes(double x, double y, double lowerPercent,
1766: double upperPercent) {
1767: // TODO: to be implemented
1768: }
1769:
1770: /**
1771: * Multiplies the range on the range axis/axes by the specified factor.
1772: *
1773: * @param x the x-coordinate (in Java2D space).
1774: * @param y the y-coordinate (in Java2D space).
1775: * @param factor the zoom factor.
1776: */
1777: public void zoomRangeAxes(double x, double y, double factor) {
1778: // TODO: to be implemented
1779: }
1780:
1781: /**
1782: * Zooms the range axes (not yet implemented).
1783: *
1784: * @param x the x-coordinate (in Java2D space).
1785: * @param y the y-coordinate (in Java2D space).
1786: * @param lowerPercent the new lower bound.
1787: * @param upperPercent the new upper bound.
1788: */
1789: public void zoomRangeAxes(double x, double y, double lowerPercent,
1790: double upperPercent) {
1791: // TODO: to be implemented
1792: }
1793:
1794: /**
1795: * Returns <code>false</code>.
1796: *
1797: * @return A boolean.
1798: */
1799: public boolean isDomainZoomable() {
1800: return false;
1801: }
1802:
1803: /**
1804: * Returns <code>false</code>.
1805: *
1806: * @return A boolean.
1807: */
1808: public boolean isRangeZoomable() {
1809: return false;
1810: }
1811:
1812: /**
1813: * Extends plot cloning to this plot type
1814: * @see org.jfree.chart.plot.Plot#clone()
1815: */
1816: public Object clone() throws CloneNotSupportedException {
1817: ContourPlot clone = (ContourPlot) super .clone();
1818:
1819: if (this .domainAxis != null) {
1820: clone.domainAxis = (ValueAxis) this .domainAxis.clone();
1821: clone.domainAxis.setPlot(clone);
1822: clone.domainAxis.addChangeListener(clone);
1823: }
1824: if (this .rangeAxis != null) {
1825: clone.rangeAxis = (ValueAxis) this .rangeAxis.clone();
1826: clone.rangeAxis.setPlot(clone);
1827: clone.rangeAxis.addChangeListener(clone);
1828: }
1829:
1830: if (clone.dataset != null) {
1831: clone.dataset.addChangeListener(clone);
1832: }
1833:
1834: if (this .colorBar != null) {
1835: clone.colorBar = (ColorBar) this .colorBar.clone();
1836: }
1837:
1838: clone.domainMarkers = (List) ObjectUtilities
1839: .deepClone(this .domainMarkers);
1840: clone.rangeMarkers = (List) ObjectUtilities
1841: .deepClone(this .rangeMarkers);
1842: clone.annotations = (List) ObjectUtilities
1843: .deepClone(this .annotations);
1844:
1845: if (this .clipPath != null) {
1846: clone.clipPath = (ClipPath) this.clipPath.clone();
1847: }
1848:
1849: return clone;
1850: }
1851:
1852: }
|