001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ---------------- 028 * ContourPlot.java 029 * ---------------- 030 * (C) Copyright 2002-2007, by David M. O'Donnell and Contributors. 031 * 032 * Original Author: David M. O'Donnell; 033 * Contributor(s): David Gilbert (for Object Refinery Limited); 034 * Arnaud Lelievre; 035 * Nicolas Brodu; 036 * 037 * $Id: ContourPlot.java,v 1.16.2.5 2007/01/31 15:56:18 mungady Exp $ 038 * 039 * Changes 040 * ------- 041 * 26-Nov-2002 : Version 1 contributed by David M. O'Donnell (DG); 042 * 14-Jan-2003 : Added crosshair attributes (DG); 043 * 23-Jan-2003 : Removed two constructors (DG); 044 * 21-Mar-2003 : Bug fix 701744 (DG); 045 * 26-Mar-2003 : Implemented Serializable (DG); 046 * 09-Jul-2003 : Changed ColorBar from extending axis classes to enclosing 047 * them (DG); 048 * 05-Aug-2003 : Applied changes in bug report 780298 (DG); 049 * 08-Sep-2003 : Added internationalization via use of properties 050 * resourceBundle (RFE 690236) (AL); 051 * 11-Sep-2003 : Cloning support (NB); 052 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 053 * 17-Jan-2004 : Removed references to DefaultContourDataset class, replaced 054 * with ContourDataset interface (with changes to the interface). 055 * See bug 741048 (DG); 056 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 057 * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); 058 * 06-Oct-2004 : Updated for changes in DatasetUtilities class (DG); 059 * 11-Nov-2004 : Renamed zoom methods to match ValueAxisPlot interface (DG); 060 * 25-Nov-2004 : Small update to clone() implementation (DG); 061 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG); 062 * 05-May-2005 : Updated draw() method parameters (DG); 063 * 16-Jun-2005 : Added default constructor (DG); 064 * 01-Sep-2005 : Moved dataAreaRatio from Plot to here (DG); 065 * ------------- JFREECHART 1.0.x --------------------------------------------- 066 * 31-Jan-2007 : Deprecated (DG); 067 * 068 */ 069 070 package org.jfree.chart.plot; 071 072 import java.awt.AlphaComposite; 073 import java.awt.Composite; 074 import java.awt.Graphics2D; 075 import java.awt.Paint; 076 import java.awt.RenderingHints; 077 import java.awt.Shape; 078 import java.awt.Stroke; 079 import java.awt.geom.Ellipse2D; 080 import java.awt.geom.GeneralPath; 081 import java.awt.geom.Line2D; 082 import java.awt.geom.Point2D; 083 import java.awt.geom.Rectangle2D; 084 import java.awt.geom.RectangularShape; 085 import java.beans.PropertyChangeEvent; 086 import java.beans.PropertyChangeListener; 087 import java.io.Serializable; 088 import java.util.Iterator; 089 import java.util.List; 090 import java.util.ResourceBundle; 091 092 import org.jfree.chart.ClipPath; 093 import org.jfree.chart.annotations.XYAnnotation; 094 import org.jfree.chart.axis.AxisSpace; 095 import org.jfree.chart.axis.ColorBar; 096 import org.jfree.chart.axis.NumberAxis; 097 import org.jfree.chart.axis.ValueAxis; 098 import org.jfree.chart.entity.ContourEntity; 099 import org.jfree.chart.entity.EntityCollection; 100 import org.jfree.chart.event.AxisChangeEvent; 101 import org.jfree.chart.event.PlotChangeEvent; 102 import org.jfree.chart.labels.ContourToolTipGenerator; 103 import org.jfree.chart.labels.StandardContourToolTipGenerator; 104 import org.jfree.chart.renderer.xy.XYBlockRenderer; 105 import org.jfree.chart.urls.XYURLGenerator; 106 import org.jfree.data.Range; 107 import org.jfree.data.contour.ContourDataset; 108 import org.jfree.data.general.DatasetChangeEvent; 109 import org.jfree.data.general.DatasetUtilities; 110 import org.jfree.ui.RectangleEdge; 111 import org.jfree.ui.RectangleInsets; 112 import org.jfree.util.ObjectUtilities; 113 114 /** 115 * A class for creating shaded contours. 116 * 117 * @deprecated This plot is no longer supported, please use {@link XYPlot} with 118 * an {@link XYBlockRenderer}. 119 */ 120 public class ContourPlot extends Plot implements ContourValuePlot, 121 ValueAxisPlot, 122 PropertyChangeListener, 123 Serializable, 124 Cloneable { 125 126 /** For serialization. */ 127 private static final long serialVersionUID = 7861072556590502247L; 128 129 /** The default insets. */ 130 protected static final RectangleInsets DEFAULT_INSETS 131 = new RectangleInsets(2.0, 2.0, 100.0, 10.0); 132 133 /** The domain axis (used for the x-values). */ 134 private ValueAxis domainAxis; 135 136 /** The range axis (used for the y-values). */ 137 private ValueAxis rangeAxis; 138 139 /** The dataset. */ 140 private ContourDataset dataset; 141 142 /** The colorbar axis (used for the z-values). */ 143 private ColorBar colorBar = null; 144 145 /** The color bar location. */ 146 private RectangleEdge colorBarLocation; 147 148 /** A flag that controls whether or not a domain crosshair is drawn..*/ 149 private boolean domainCrosshairVisible; 150 151 /** The domain crosshair value. */ 152 private double domainCrosshairValue; 153 154 /** The pen/brush used to draw the crosshair (if any). */ 155 private transient Stroke domainCrosshairStroke; 156 157 /** The color used to draw the crosshair (if any). */ 158 private transient Paint domainCrosshairPaint; 159 160 /** 161 * A flag that controls whether or not the crosshair locks onto actual data 162 * points. 163 */ 164 private boolean domainCrosshairLockedOnData = true; 165 166 /** A flag that controls whether or not a range crosshair is drawn..*/ 167 private boolean rangeCrosshairVisible; 168 169 /** The range crosshair value. */ 170 private double rangeCrosshairValue; 171 172 /** The pen/brush used to draw the crosshair (if any). */ 173 private transient Stroke rangeCrosshairStroke; 174 175 /** The color used to draw the crosshair (if any). */ 176 private transient Paint rangeCrosshairPaint; 177 178 /** 179 * A flag that controls whether or not the crosshair locks onto actual data 180 * points. 181 */ 182 private boolean rangeCrosshairLockedOnData = true; 183 184 /** 185 * Defines dataArea rectangle as the ratio formed from dividing height by 186 * width (of the dataArea). Modifies plot area calculations. 187 * ratio>0 will attempt to layout the plot so that the 188 * dataArea.height/dataArea.width = ratio. 189 * ratio<0 will attempt to layout the plot so that the 190 * dataArea.height/dataArea.width in plot units (not java2D units as when 191 * ratio>0) = -1.*ratio. 192 */ //dmo 193 private double dataAreaRatio = 0.0; //zero when the parameter is not set 194 195 /** A list of markers (optional) for the domain axis. */ 196 private List domainMarkers; 197 198 /** A list of markers (optional) for the range axis. */ 199 private List rangeMarkers; 200 201 /** A list of annotations (optional) for the plot. */ 202 private List annotations; 203 204 /** The tool tip generator. */ 205 private ContourToolTipGenerator toolTipGenerator; 206 207 /** The URL text generator. */ 208 private XYURLGenerator urlGenerator; 209 210 /** 211 * Controls whether data are render as filled rectangles or rendered as 212 * points 213 */ 214 private boolean renderAsPoints = false; 215 216 /** 217 * Size of points rendered when renderAsPoints = true. Size is relative to 218 * dataArea 219 */ 220 private double ptSizePct = 0.05; 221 222 /** Contains the a ClipPath to "trim" the contours. */ 223 private transient ClipPath clipPath = null; 224 225 /** Set to Paint to represent missing values. */ 226 private transient Paint missingPaint = null; 227 228 /** The resourceBundle for the localization. */ 229 protected static ResourceBundle localizationResources = 230 ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle"); 231 232 /** 233 * Creates a new plot with no dataset or axes. 234 */ 235 public ContourPlot() { 236 this(null, null, null, null); 237 } 238 239 /** 240 * Constructs a contour plot with the specified axes (other attributes take 241 * default values). 242 * 243 * @param dataset The dataset. 244 * @param domainAxis The domain axis. 245 * @param rangeAxis The range axis. 246 * @param colorBar The z-axis axis. 247 */ 248 public ContourPlot(ContourDataset dataset, 249 ValueAxis domainAxis, ValueAxis rangeAxis, 250 ColorBar colorBar) { 251 252 super(); 253 254 this.dataset = dataset; 255 if (dataset != null) { 256 dataset.addChangeListener(this); 257 } 258 259 this.domainAxis = domainAxis; 260 if (domainAxis != null) { 261 domainAxis.setPlot(this); 262 domainAxis.addChangeListener(this); 263 } 264 265 this.rangeAxis = rangeAxis; 266 if (rangeAxis != null) { 267 rangeAxis.setPlot(this); 268 rangeAxis.addChangeListener(this); 269 } 270 271 this.colorBar = colorBar; 272 if (colorBar != null) { 273 colorBar.getAxis().setPlot(this); 274 colorBar.getAxis().addChangeListener(this); 275 colorBar.configure(this); 276 } 277 this.colorBarLocation = RectangleEdge.LEFT; 278 279 this.toolTipGenerator = new StandardContourToolTipGenerator(); 280 281 } 282 283 /** 284 * Returns the color bar location. 285 * 286 * @return The color bar location. 287 */ 288 public RectangleEdge getColorBarLocation() { 289 return this.colorBarLocation; 290 } 291 292 /** 293 * Sets the color bar location and sends a {@link PlotChangeEvent} to all 294 * registered listeners. 295 * 296 * @param edge the location. 297 */ 298 public void setColorBarLocation(RectangleEdge edge) { 299 this.colorBarLocation = edge; 300 notifyListeners(new PlotChangeEvent(this)); 301 } 302 303 /** 304 * Returns the primary dataset for the plot. 305 * 306 * @return The primary dataset (possibly <code>null</code>). 307 */ 308 public ContourDataset getDataset() { 309 return this.dataset; 310 } 311 312 /** 313 * Sets the dataset for the plot, replacing the existing dataset if there 314 * is one. 315 * 316 * @param dataset the dataset (<code>null</code> permitted). 317 */ 318 public void setDataset(ContourDataset dataset) { 319 320 // if there is an existing dataset, remove the plot from the list of 321 // change listeners... 322 ContourDataset existing = this.dataset; 323 if (existing != null) { 324 existing.removeChangeListener(this); 325 } 326 327 // set the new dataset, and register the chart as a change listener... 328 this.dataset = dataset; 329 if (dataset != null) { 330 setDatasetGroup(dataset.getGroup()); 331 dataset.addChangeListener(this); 332 } 333 334 // send a dataset change event to self... 335 DatasetChangeEvent event = new DatasetChangeEvent(this, dataset); 336 datasetChanged(event); 337 338 } 339 340 /** 341 * Returns the domain axis for the plot. 342 * 343 * @return The domain axis. 344 */ 345 public ValueAxis getDomainAxis() { 346 347 ValueAxis result = this.domainAxis; 348 349 return result; 350 351 } 352 353 /** 354 * Sets the domain axis for the plot (this must be compatible with the plot 355 * type or an exception is thrown). 356 * 357 * @param axis The new axis. 358 */ 359 public void setDomainAxis(ValueAxis axis) { 360 361 if (isCompatibleDomainAxis(axis)) { 362 363 if (axis != null) { 364 axis.setPlot(this); 365 axis.addChangeListener(this); 366 } 367 368 // plot is likely registered as a listener with the existing axis... 369 if (this.domainAxis != null) { 370 this.domainAxis.removeChangeListener(this); 371 } 372 373 this.domainAxis = axis; 374 notifyListeners(new PlotChangeEvent(this)); 375 376 } 377 378 } 379 380 /** 381 * Returns the range axis for the plot. 382 * 383 * @return The range axis. 384 */ 385 public ValueAxis getRangeAxis() { 386 387 ValueAxis result = this.rangeAxis; 388 389 return result; 390 391 } 392 393 /** 394 * Sets the range axis for the plot. 395 * <P> 396 * An exception is thrown if the new axis and the plot are not mutually 397 * compatible. 398 * 399 * @param axis The new axis (null permitted). 400 */ 401 public void setRangeAxis(ValueAxis axis) { 402 403 if (axis != null) { 404 axis.setPlot(this); 405 axis.addChangeListener(this); 406 } 407 408 // plot is likely registered as a listener with the existing axis... 409 if (this.rangeAxis != null) { 410 this.rangeAxis.removeChangeListener(this); 411 } 412 413 this.rangeAxis = axis; 414 notifyListeners(new PlotChangeEvent(this)); 415 416 } 417 418 /** 419 * Sets the colorbar for the plot. 420 * 421 * @param axis The new axis (null permitted). 422 */ 423 public void setColorBarAxis(ColorBar axis) { 424 425 this.colorBar = axis; 426 notifyListeners(new PlotChangeEvent(this)); 427 428 } 429 430 /** 431 * Returns the data area ratio. 432 * 433 * @return The ratio. 434 */ 435 public double getDataAreaRatio() { 436 return this.dataAreaRatio; 437 } 438 439 /** 440 * Sets the data area ratio. 441 * 442 * @param ratio the ratio. 443 */ 444 public void setDataAreaRatio(double ratio) { 445 this.dataAreaRatio = ratio; 446 } 447 448 /** 449 * Adds a marker for the domain axis. 450 * <P> 451 * Typically a marker will be drawn by the renderer as a line perpendicular 452 * to the range axis, however this is entirely up to the renderer. 453 * 454 * @param marker the marker. 455 */ 456 public void addDomainMarker(Marker marker) { 457 458 if (this.domainMarkers == null) { 459 this.domainMarkers = new java.util.ArrayList(); 460 } 461 this.domainMarkers.add(marker); 462 notifyListeners(new PlotChangeEvent(this)); 463 464 } 465 466 /** 467 * Clears all the domain markers. 468 */ 469 public void clearDomainMarkers() { 470 if (this.domainMarkers != null) { 471 this.domainMarkers.clear(); 472 notifyListeners(new PlotChangeEvent(this)); 473 } 474 } 475 476 /** 477 * Adds a marker for the range axis. 478 * <P> 479 * Typically a marker will be drawn by the renderer as a line perpendicular 480 * to the range axis, however this is entirely up to the renderer. 481 * 482 * @param marker The marker. 483 */ 484 public void addRangeMarker(Marker marker) { 485 486 if (this.rangeMarkers == null) { 487 this.rangeMarkers = new java.util.ArrayList(); 488 } 489 this.rangeMarkers.add(marker); 490 notifyListeners(new PlotChangeEvent(this)); 491 492 } 493 494 /** 495 * Clears all the range markers. 496 */ 497 public void clearRangeMarkers() { 498 if (this.rangeMarkers != null) { 499 this.rangeMarkers.clear(); 500 notifyListeners(new PlotChangeEvent(this)); 501 } 502 } 503 504 /** 505 * Adds an annotation to the plot. 506 * 507 * @param annotation the annotation. 508 */ 509 public void addAnnotation(XYAnnotation annotation) { 510 511 if (this.annotations == null) { 512 this.annotations = new java.util.ArrayList(); 513 } 514 this.annotations.add(annotation); 515 notifyListeners(new PlotChangeEvent(this)); 516 517 } 518 519 /** 520 * Clears all the annotations. 521 */ 522 public void clearAnnotations() { 523 if (this.annotations != null) { 524 this.annotations.clear(); 525 notifyListeners(new PlotChangeEvent(this)); 526 } 527 } 528 529 /** 530 * Checks the compatibility of a domain axis, returning true if the axis is 531 * compatible with the plot, and false otherwise. 532 * 533 * @param axis The proposed axis. 534 * 535 * @return <code>true</code> if the axis is compatible with the plot. 536 */ 537 public boolean isCompatibleDomainAxis(ValueAxis axis) { 538 539 return true; 540 541 } 542 543 /** 544 * Draws the plot on a Java 2D graphics device (such as the screen or a 545 * printer). 546 * <P> 547 * The optional <code>info</code> argument collects information about the 548 * rendering of the plot (dimensions, tooltip information etc). Just pass 549 * in <code>null</code> if you do not need this information. 550 * 551 * @param g2 the graphics device. 552 * @param area the area within which the plot (including axis labels) 553 * should be drawn. 554 * @param anchor the anchor point (<code>null</code> permitted). 555 * @param parentState the state from the parent plot, if there is one. 556 * @param info collects chart drawing information (<code>null</code> 557 * permitted). 558 */ 559 public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, 560 PlotState parentState, 561 PlotRenderingInfo info) { 562 563 // if the plot area is too small, just return... 564 boolean b1 = (area.getWidth() <= MINIMUM_WIDTH_TO_DRAW); 565 boolean b2 = (area.getHeight() <= MINIMUM_HEIGHT_TO_DRAW); 566 if (b1 || b2) { 567 return; 568 } 569 570 // record the plot area... 571 if (info != null) { 572 info.setPlotArea(area); 573 } 574 575 // adjust the drawing area for plot insets (if any)... 576 RectangleInsets insets = getInsets(); 577 insets.trim(area); 578 579 AxisSpace space = new AxisSpace(); 580 581 space = this.domainAxis.reserveSpace(g2, this, area, 582 RectangleEdge.BOTTOM, space); 583 space = this.rangeAxis.reserveSpace(g2, this, area, 584 RectangleEdge.LEFT, space); 585 586 Rectangle2D estimatedDataArea = space.shrink(area, null); 587 588 AxisSpace space2 = new AxisSpace(); 589 space2 = this.colorBar.reserveSpace(g2, this, area, estimatedDataArea, 590 this.colorBarLocation, space2); 591 Rectangle2D adjustedPlotArea = space2.shrink(area, null); 592 593 Rectangle2D dataArea = space.shrink(adjustedPlotArea, null); 594 595 Rectangle2D colorBarArea = space2.reserved(area, this.colorBarLocation); 596 597 // additional dataArea modifications 598 if (getDataAreaRatio() != 0.0) { //check whether modification is 599 double ratio = getDataAreaRatio(); 600 Rectangle2D tmpDataArea = (Rectangle2D) dataArea.clone(); 601 double h = tmpDataArea.getHeight(); 602 double w = tmpDataArea.getWidth(); 603 604 if (ratio > 0) { // ratio represents pixels 605 if (w * ratio <= h) { 606 h = ratio * w; 607 } 608 else { 609 w = h / ratio; 610 } 611 } 612 else { // ratio represents axis units 613 ratio *= -1.0; 614 double xLength = getDomainAxis().getRange().getLength(); 615 double yLength = getRangeAxis().getRange().getLength(); 616 double unitRatio = yLength / xLength; 617 618 ratio = unitRatio * ratio; 619 620 if (w * ratio <= h) { 621 h = ratio * w; 622 } 623 else { 624 w = h / ratio; 625 } 626 } 627 628 dataArea.setRect(tmpDataArea.getX() + tmpDataArea.getWidth() / 2 629 - w / 2, tmpDataArea.getY(), w, h); 630 } 631 632 if (info != null) { 633 info.setDataArea(dataArea); 634 } 635 636 CrosshairState crosshairState = new CrosshairState(); 637 crosshairState.setCrosshairDistance(Double.POSITIVE_INFINITY); 638 639 // draw the plot background... 640 drawBackground(g2, dataArea); 641 642 double cursor = dataArea.getMaxY(); 643 if (this.domainAxis != null) { 644 this.domainAxis.draw(g2, cursor, adjustedPlotArea, dataArea, 645 RectangleEdge.BOTTOM, info); 646 } 647 648 if (this.rangeAxis != null) { 649 cursor = dataArea.getMinX(); 650 this.rangeAxis.draw(g2, cursor, adjustedPlotArea, dataArea, 651 RectangleEdge.LEFT, info); 652 } 653 654 if (this.colorBar != null) { 655 cursor = 0.0; 656 cursor = this.colorBar.draw(g2, cursor, adjustedPlotArea, dataArea, 657 colorBarArea, this.colorBarLocation); 658 } 659 Shape originalClip = g2.getClip(); 660 Composite originalComposite = g2.getComposite(); 661 662 g2.clip(dataArea); 663 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 664 getForegroundAlpha())); 665 render(g2, dataArea, info, crosshairState); 666 667 if (this.domainMarkers != null) { 668 Iterator iterator = this.domainMarkers.iterator(); 669 while (iterator.hasNext()) { 670 Marker marker = (Marker) iterator.next(); 671 drawDomainMarker(g2, this, getDomainAxis(), marker, dataArea); 672 } 673 } 674 675 if (this.rangeMarkers != null) { 676 Iterator iterator = this.rangeMarkers.iterator(); 677 while (iterator.hasNext()) { 678 Marker marker = (Marker) iterator.next(); 679 drawRangeMarker(g2, this, getRangeAxis(), marker, dataArea); 680 } 681 } 682 683 // TO DO: these annotations only work with XYPlot, see if it is possible to 684 // make ContourPlot a subclass of XYPlot (DG); 685 686 // // draw the annotations... 687 // if (this.annotations != null) { 688 // Iterator iterator = this.annotations.iterator(); 689 // while (iterator.hasNext()) { 690 // Annotation annotation = (Annotation) iterator.next(); 691 // if (annotation instanceof XYAnnotation) { 692 // XYAnnotation xya = (XYAnnotation) annotation; 693 // // get the annotation to draw itself... 694 // xya.draw(g2, this, dataArea, getDomainAxis(), 695 // getRangeAxis()); 696 // } 697 // } 698 // } 699 700 g2.setClip(originalClip); 701 g2.setComposite(originalComposite); 702 drawOutline(g2, dataArea); 703 704 } 705 706 /** 707 * Draws a representation of the data within the dataArea region, using the 708 * current renderer. 709 * <P> 710 * The <code>info</code> and <code>crosshairState</code> arguments may be 711 * <code>null</code>. 712 * 713 * @param g2 the graphics device. 714 * @param dataArea the region in which the data is to be drawn. 715 * @param info an optional object for collection dimension information. 716 * @param crosshairState an optional object for collecting crosshair info. 717 */ 718 public void render(Graphics2D g2, Rectangle2D dataArea, 719 PlotRenderingInfo info, CrosshairState crosshairState) { 720 721 // now get the data and plot it (the visual representation will depend 722 // on the renderer that has been set)... 723 ContourDataset data = getDataset(); 724 if (data != null) { 725 726 ColorBar zAxis = getColorBar(); 727 728 if (this.clipPath != null) { 729 GeneralPath clipper = getClipPath().draw(g2, dataArea, 730 this.domainAxis, this.rangeAxis); 731 if (this.clipPath.isClip()) { 732 g2.clip(clipper); 733 } 734 } 735 736 if (this.renderAsPoints) { 737 pointRenderer(g2, dataArea, info, this, this.domainAxis, 738 this.rangeAxis, zAxis, data, crosshairState); 739 } 740 else { 741 contourRenderer(g2, dataArea, info, this, this.domainAxis, 742 this.rangeAxis, zAxis, data, crosshairState); 743 } 744 745 // draw vertical crosshair if required... 746 setDomainCrosshairValue(crosshairState.getCrosshairX(), false); 747 if (isDomainCrosshairVisible()) { 748 drawVerticalLine(g2, dataArea, 749 getDomainCrosshairValue(), 750 getDomainCrosshairStroke(), 751 getDomainCrosshairPaint()); 752 } 753 754 // draw horizontal crosshair if required... 755 setRangeCrosshairValue(crosshairState.getCrosshairY(), false); 756 if (isRangeCrosshairVisible()) { 757 drawHorizontalLine(g2, dataArea, 758 getRangeCrosshairValue(), 759 getRangeCrosshairStroke(), 760 getRangeCrosshairPaint()); 761 } 762 763 } 764 else if (this.clipPath != null) { 765 getClipPath().draw(g2, dataArea, this.domainAxis, this.rangeAxis); 766 } 767 768 } 769 770 /** 771 * Fills the plot. 772 * 773 * @param g2 the graphics device. 774 * @param dataArea the area within which the data is being drawn. 775 * @param info collects information about the drawing. 776 * @param plot the plot (can be used to obtain standard color 777 * information etc). 778 * @param horizontalAxis the domain (horizontal) axis. 779 * @param verticalAxis the range (vertical) axis. 780 * @param colorBar the color bar axis. 781 * @param data the dataset. 782 * @param crosshairState information about crosshairs on a plot. 783 */ 784 public void contourRenderer(Graphics2D g2, 785 Rectangle2D dataArea, 786 PlotRenderingInfo info, 787 ContourPlot plot, 788 ValueAxis horizontalAxis, 789 ValueAxis verticalAxis, 790 ColorBar colorBar, 791 ContourDataset data, 792 CrosshairState crosshairState) { 793 794 // setup for collecting optional entity info... 795 Rectangle2D.Double entityArea = null; 796 EntityCollection entities = null; 797 if (info != null) { 798 entities = info.getOwner().getEntityCollection(); 799 } 800 801 Rectangle2D.Double rect = null; 802 rect = new Rectangle2D.Double(); 803 804 //turn off anti-aliasing when filling rectangles 805 Object antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); 806 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 807 RenderingHints.VALUE_ANTIALIAS_OFF); 808 809 // get the data points 810 Number[] xNumber = data.getXValues(); 811 Number[] yNumber = data.getYValues(); 812 Number[] zNumber = data.getZValues(); 813 814 double[] x = new double[xNumber.length]; 815 double[] y = new double[yNumber.length]; 816 817 for (int i = 0; i < x.length; i++) { 818 x[i] = xNumber[i].doubleValue(); 819 y[i] = yNumber[i].doubleValue(); 820 } 821 822 int[] xIndex = data.indexX(); 823 int[] indexX = data.getXIndices(); 824 boolean vertInverted = ((NumberAxis) verticalAxis).isInverted(); 825 boolean horizInverted = false; 826 if (horizontalAxis instanceof NumberAxis) { 827 horizInverted = ((NumberAxis) horizontalAxis).isInverted(); 828 } 829 double transX = 0.0; 830 double transXm1 = 0.0; 831 double transXp1 = 0.0; 832 double transDXm1 = 0.0; 833 double transDXp1 = 0.0; 834 double transDX = 0.0; 835 double transY = 0.0; 836 double transYm1 = 0.0; 837 double transYp1 = 0.0; 838 double transDYm1 = 0.0; 839 double transDYp1 = 0.0; 840 double transDY = 0.0; 841 int iMax = xIndex[xIndex.length - 1]; 842 for (int k = 0; k < x.length; k++) { 843 int i = xIndex[k]; 844 if (indexX[i] == k) { // this is a new column 845 if (i == 0) { 846 transX = horizontalAxis.valueToJava2D(x[k], dataArea, 847 RectangleEdge.BOTTOM); 848 transXm1 = transX; 849 transXp1 = horizontalAxis.valueToJava2D( 850 x[indexX[i + 1]], dataArea, RectangleEdge.BOTTOM); 851 transDXm1 = Math.abs(0.5 * (transX - transXm1)); 852 transDXp1 = Math.abs(0.5 * (transX - transXp1)); 853 } 854 else if (i == iMax) { 855 transX = horizontalAxis.valueToJava2D(x[k], dataArea, 856 RectangleEdge.BOTTOM); 857 transXm1 = horizontalAxis.valueToJava2D(x[indexX[i - 1]], 858 dataArea, RectangleEdge.BOTTOM); 859 transXp1 = transX; 860 transDXm1 = Math.abs(0.5 * (transX - transXm1)); 861 transDXp1 = Math.abs(0.5 * (transX - transXp1)); 862 } 863 else { 864 transX = horizontalAxis.valueToJava2D(x[k], dataArea, 865 RectangleEdge.BOTTOM); 866 transXp1 = horizontalAxis.valueToJava2D(x[indexX[i + 1]], 867 dataArea, RectangleEdge.BOTTOM); 868 transDXm1 = transDXp1; 869 transDXp1 = Math.abs(0.5 * (transX - transXp1)); 870 } 871 872 if (horizInverted) { 873 transX -= transDXp1; 874 } 875 else { 876 transX -= transDXm1; 877 } 878 879 transDX = transDXm1 + transDXp1; 880 881 transY = verticalAxis.valueToJava2D(y[k], dataArea, 882 RectangleEdge.LEFT); 883 transYm1 = transY; 884 if (k + 1 == y.length) { 885 continue; 886 } 887 transYp1 = verticalAxis.valueToJava2D(y[k + 1], dataArea, 888 RectangleEdge.LEFT); 889 transDYm1 = Math.abs(0.5 * (transY - transYm1)); 890 transDYp1 = Math.abs(0.5 * (transY - transYp1)); 891 } 892 else if ((i < indexX.length - 1 893 && indexX[i + 1] - 1 == k) || k == x.length - 1) { 894 // end of column 895 transY = verticalAxis.valueToJava2D(y[k], dataArea, 896 RectangleEdge.LEFT); 897 transYm1 = verticalAxis.valueToJava2D(y[k - 1], dataArea, 898 RectangleEdge.LEFT); 899 transYp1 = transY; 900 transDYm1 = Math.abs(0.5 * (transY - transYm1)); 901 transDYp1 = Math.abs(0.5 * (transY - transYp1)); 902 } 903 else { 904 transY = verticalAxis.valueToJava2D(y[k], dataArea, 905 RectangleEdge.LEFT); 906 transYp1 = verticalAxis.valueToJava2D(y[k + 1], dataArea, 907 RectangleEdge.LEFT); 908 transDYm1 = transDYp1; 909 transDYp1 = Math.abs(0.5 * (transY - transYp1)); 910 } 911 if (vertInverted) { 912 transY -= transDYm1; 913 } 914 else { 915 transY -= transDYp1; 916 } 917 918 transDY = transDYm1 + transDYp1; 919 920 rect.setRect(transX, transY, transDX, transDY); 921 if (zNumber[k] != null) { 922 g2.setPaint(colorBar.getPaint(zNumber[k].doubleValue())); 923 g2.fill(rect); 924 } 925 else if (this.missingPaint != null) { 926 g2.setPaint(this.missingPaint); 927 g2.fill(rect); 928 } 929 930 entityArea = rect; 931 932 // add an entity for the item... 933 if (entities != null) { 934 String tip = ""; 935 if (getToolTipGenerator() != null) { 936 tip = this.toolTipGenerator.generateToolTip(data, k); 937 } 938 // Shape s = g2.getClip(); 939 // if (s.contains(rect) || s.intersects(rect)) { 940 String url = null; 941 // if (getURLGenerator() != null) { //dmo: look at this later 942 // url = getURLGenerator().generateURL(data, series, item); 943 // } 944 // Unlike XYItemRenderer, we need to clone entityArea since it 945 // reused. 946 ContourEntity entity = new ContourEntity( 947 (Rectangle2D.Double) entityArea.clone(), tip, url); 948 entity.setIndex(k); 949 entities.add(entity); 950 // } 951 } 952 953 // do we need to update the crosshair values? 954 if (plot.isDomainCrosshairLockedOnData()) { 955 if (plot.isRangeCrosshairLockedOnData()) { 956 // both axes 957 crosshairState.updateCrosshairPoint(x[k], y[k], transX, 958 transY, PlotOrientation.VERTICAL); 959 } 960 else { 961 // just the horizontal axis... 962 crosshairState.updateCrosshairX(transX); 963 } 964 } 965 else { 966 if (plot.isRangeCrosshairLockedOnData()) { 967 // just the vertical axis... 968 crosshairState.updateCrosshairY(transY); 969 } 970 } 971 } 972 973 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias); 974 975 return; 976 977 } 978 979 /** 980 * Draws the visual representation of a single data item. 981 * 982 * @param g2 the graphics device. 983 * @param dataArea the area within which the data is being drawn. 984 * @param info collects information about the drawing. 985 * @param plot the plot (can be used to obtain standard color 986 * information etc). 987 * @param domainAxis the domain (horizontal) axis. 988 * @param rangeAxis the range (vertical) axis. 989 * @param colorBar the color bar axis. 990 * @param data the dataset. 991 * @param crosshairState information about crosshairs on a plot. 992 */ 993 public void pointRenderer(Graphics2D g2, 994 Rectangle2D dataArea, 995 PlotRenderingInfo info, 996 ContourPlot plot, 997 ValueAxis domainAxis, 998 ValueAxis rangeAxis, 999 ColorBar colorBar, 1000 ContourDataset data, 1001 CrosshairState crosshairState) { 1002 1003 // setup for collecting optional entity info... 1004 RectangularShape entityArea = null; 1005 EntityCollection entities = null; 1006 if (info != null) { 1007 entities = info.getOwner().getEntityCollection(); 1008 } 1009 1010 // Rectangle2D.Double rect = null; 1011 // rect = new Rectangle2D.Double(); 1012 RectangularShape rect = new Ellipse2D.Double(); 1013 1014 1015 //turn off anti-aliasing when filling rectangles 1016 Object antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING); 1017 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 1018 RenderingHints.VALUE_ANTIALIAS_OFF); 1019 1020 // if (tooltips!=null) tooltips.clearToolTips(); // reset collection 1021 // get the data points 1022 Number[] xNumber = data.getXValues(); 1023 Number[] yNumber = data.getYValues(); 1024 Number[] zNumber = data.getZValues(); 1025 1026 double[] x = new double[xNumber.length]; 1027 double[] y = new double[yNumber.length]; 1028 1029 for (int i = 0; i < x.length; i++) { 1030 x[i] = xNumber[i].doubleValue(); 1031 y[i] = yNumber[i].doubleValue(); 1032 } 1033 1034 double transX = 0.0; 1035 double transDX = 0.0; 1036 double transY = 0.0; 1037 double transDY = 0.0; 1038 double size = dataArea.getWidth() * this.ptSizePct; 1039 for (int k = 0; k < x.length; k++) { 1040 1041 transX = domainAxis.valueToJava2D(x[k], dataArea, 1042 RectangleEdge.BOTTOM) - 0.5 * size; 1043 transY = rangeAxis.valueToJava2D(y[k], dataArea, RectangleEdge.LEFT) 1044 - 0.5 * size; 1045 transDX = size; 1046 transDY = size; 1047 1048 rect.setFrame(transX, transY, transDX, transDY); 1049 1050 if (zNumber[k] != null) { 1051 g2.setPaint(colorBar.getPaint(zNumber[k].doubleValue())); 1052 g2.fill(rect); 1053 } 1054 else if (this.missingPaint != null) { 1055 g2.setPaint(this.missingPaint); 1056 g2.fill(rect); 1057 } 1058 1059 1060 entityArea = rect; 1061 1062 // add an entity for the item... 1063 if (entities != null) { 1064 String tip = null; 1065 if (getToolTipGenerator() != null) { 1066 tip = this.toolTipGenerator.generateToolTip(data, k); 1067 } 1068 String url = null; 1069 // if (getURLGenerator() != null) { //dmo: look at this later 1070 // url = getURLGenerator().generateURL(data, series, item); 1071 // } 1072 // Unlike XYItemRenderer, we need to clone entityArea since it 1073 // reused. 1074 ContourEntity entity = new ContourEntity( 1075 (RectangularShape) entityArea.clone(), tip, url); 1076 entity.setIndex(k); 1077 entities.add(entity); 1078 } 1079 1080 // do we need to update the crosshair values? 1081 if (plot.isDomainCrosshairLockedOnData()) { 1082 if (plot.isRangeCrosshairLockedOnData()) { 1083 // both axes 1084 crosshairState.updateCrosshairPoint(x[k], y[k], transX, 1085 transY, PlotOrientation.VERTICAL); 1086 } 1087 else { 1088 // just the horizontal axis... 1089 crosshairState.updateCrosshairX(transX); 1090 } 1091 } 1092 else { 1093 if (plot.isRangeCrosshairLockedOnData()) { 1094 // just the vertical axis... 1095 crosshairState.updateCrosshairY(transY); 1096 } 1097 } 1098 } 1099 1100 1101 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias); 1102 1103 return; 1104 1105 } 1106 1107 /** 1108 * Utility method for drawing a crosshair on the chart (if required). 1109 * 1110 * @param g2 The graphics device. 1111 * @param dataArea The data area. 1112 * @param value The coordinate, where to draw the line. 1113 * @param stroke The stroke to use. 1114 * @param paint The paint to use. 1115 */ 1116 protected void drawVerticalLine(Graphics2D g2, Rectangle2D dataArea, 1117 double value, Stroke stroke, Paint paint) { 1118 1119 double xx = getDomainAxis().valueToJava2D(value, dataArea, 1120 RectangleEdge.BOTTOM); 1121 Line2D line = new Line2D.Double(xx, dataArea.getMinY(), xx, 1122 dataArea.getMaxY()); 1123 g2.setStroke(stroke); 1124 g2.setPaint(paint); 1125 g2.draw(line); 1126 1127 } 1128 1129 /** 1130 * Utility method for drawing a crosshair on the chart (if required). 1131 * 1132 * @param g2 The graphics device. 1133 * @param dataArea The data area. 1134 * @param value The coordinate, where to draw the line. 1135 * @param stroke The stroke to use. 1136 * @param paint The paint to use. 1137 */ 1138 protected void drawHorizontalLine(Graphics2D g2, Rectangle2D dataArea, 1139 double value, Stroke stroke, 1140 Paint paint) { 1141 1142 double yy = getRangeAxis().valueToJava2D(value, dataArea, 1143 RectangleEdge.LEFT); 1144 Line2D line = new Line2D.Double(dataArea.getMinX(), yy, 1145 dataArea.getMaxX(), yy); 1146 g2.setStroke(stroke); 1147 g2.setPaint(paint); 1148 g2.draw(line); 1149 1150 } 1151 1152 /** 1153 * Handles a 'click' on the plot by updating the anchor values... 1154 * 1155 * @param x x-coordinate, where the click occured. 1156 * @param y y-coordinate, where the click occured. 1157 * @param info An object for collection dimension information. 1158 */ 1159 public void handleClick(int x, int y, PlotRenderingInfo info) { 1160 1161 /* // set the anchor value for the horizontal axis... 1162 ValueAxis hva = getDomainAxis(); 1163 if (hva != null) { 1164 double hvalue = hva.translateJava2DtoValue( 1165 (float) x, info.getDataArea() 1166 ); 1167 1168 hva.setAnchorValue(hvalue); 1169 setDomainCrosshairValue(hvalue); 1170 } 1171 1172 // set the anchor value for the vertical axis... 1173 ValueAxis vva = getRangeAxis(); 1174 if (vva != null) { 1175 double vvalue = vva.translateJava2DtoValue( 1176 (float) y, info.getDataArea() 1177 ); 1178 vva.setAnchorValue(vvalue); 1179 setRangeCrosshairValue(vvalue); 1180 } 1181 */ 1182 } 1183 1184 /** 1185 * Zooms the axis ranges by the specified percentage about the anchor point. 1186 * 1187 * @param percent The amount of the zoom. 1188 */ 1189 public void zoom(double percent) { 1190 1191 if (percent > 0) { 1192 // double range = this.domainAxis.getRange().getLength(); 1193 // double scaledRange = range * percent; 1194 // domainAxis.setAnchoredRange(scaledRange); 1195 1196 // range = this.rangeAxis.getRange().getLength(); 1197 // scaledRange = range * percent; 1198 // rangeAxis.setAnchoredRange(scaledRange); 1199 } 1200 else { 1201 getRangeAxis().setAutoRange(true); 1202 getDomainAxis().setAutoRange(true); 1203 } 1204 1205 } 1206 1207 /** 1208 * Returns the plot type as a string. 1209 * 1210 * @return A short string describing the type of plot. 1211 */ 1212 public String getPlotType() { 1213 return localizationResources.getString("Contour_Plot"); 1214 } 1215 1216 /** 1217 * Returns the range for an axis. 1218 * 1219 * @param axis the axis. 1220 * 1221 * @return The range for an axis. 1222 */ 1223 public Range getDataRange(ValueAxis axis) { 1224 1225 if (this.dataset == null) { 1226 return null; 1227 } 1228 1229 Range result = null; 1230 1231 if (axis == getDomainAxis()) { 1232 result = DatasetUtilities.findDomainBounds(this.dataset); 1233 } 1234 else if (axis == getRangeAxis()) { 1235 result = DatasetUtilities.findRangeBounds(this.dataset); 1236 } 1237 1238 return result; 1239 1240 } 1241 1242 /** 1243 * Returns the range for the Contours. 1244 * 1245 * @return The range for the Contours (z-axis). 1246 */ 1247 public Range getContourDataRange() { 1248 1249 Range result = null; 1250 1251 ContourDataset data = getDataset(); 1252 1253 if (data != null) { 1254 Range h = getDomainAxis().getRange(); 1255 Range v = getRangeAxis().getRange(); 1256 result = this.visibleRange(data, h, v); 1257 } 1258 1259 return result; 1260 } 1261 1262 /** 1263 * Notifies all registered listeners of a property change. 1264 * <P> 1265 * One source of property change events is the plot's renderer. 1266 * 1267 * @param event Information about the property change. 1268 */ 1269 public void propertyChange(PropertyChangeEvent event) { 1270 notifyListeners(new PlotChangeEvent(this)); 1271 } 1272 1273 /** 1274 * Receives notification of a change to the plot's dataset. 1275 * <P> 1276 * The chart reacts by passing on a chart change event to all registered 1277 * listeners. 1278 * 1279 * @param event Information about the event (not used here). 1280 */ 1281 public void datasetChanged(DatasetChangeEvent event) { 1282 if (this.domainAxis != null) { 1283 this.domainAxis.configure(); 1284 } 1285 if (this.rangeAxis != null) { 1286 this.rangeAxis.configure(); 1287 } 1288 if (this.colorBar != null) { 1289 this.colorBar.configure(this); 1290 } 1291 super.datasetChanged(event); 1292 } 1293 1294 /** 1295 * Returns the colorbar. 1296 * 1297 * @return The colorbar. 1298 */ 1299 public ColorBar getColorBar() { 1300 return this.colorBar; 1301 } 1302 1303 /** 1304 * Returns a flag indicating whether or not the domain crosshair is visible. 1305 * 1306 * @return The flag. 1307 */ 1308 public boolean isDomainCrosshairVisible() { 1309 return this.domainCrosshairVisible; 1310 } 1311 1312 /** 1313 * Sets the flag indicating whether or not the domain crosshair is visible. 1314 * 1315 * @param flag the new value of the flag. 1316 */ 1317 public void setDomainCrosshairVisible(boolean flag) { 1318 1319 if (this.domainCrosshairVisible != flag) { 1320 this.domainCrosshairVisible = flag; 1321 notifyListeners(new PlotChangeEvent(this)); 1322 } 1323 1324 } 1325 1326 /** 1327 * Returns a flag indicating whether or not the crosshair should "lock-on" 1328 * to actual data values. 1329 * 1330 * @return The flag. 1331 */ 1332 public boolean isDomainCrosshairLockedOnData() { 1333 return this.domainCrosshairLockedOnData; 1334 } 1335 1336 /** 1337 * Sets the flag indicating whether or not the domain crosshair should 1338 * "lock-on" to actual data values. 1339 * 1340 * @param flag the flag. 1341 */ 1342 public void setDomainCrosshairLockedOnData(boolean flag) { 1343 if (this.domainCrosshairLockedOnData != flag) { 1344 this.domainCrosshairLockedOnData = flag; 1345 notifyListeners(new PlotChangeEvent(this)); 1346 } 1347 } 1348 1349 /** 1350 * Returns the domain crosshair value. 1351 * 1352 * @return The value. 1353 */ 1354 public double getDomainCrosshairValue() { 1355 return this.domainCrosshairValue; 1356 } 1357 1358 /** 1359 * Sets the domain crosshair value. 1360 * <P> 1361 * Registered listeners are notified that the plot has been modified, but 1362 * only if the crosshair is visible. 1363 * 1364 * @param value the new value. 1365 */ 1366 public void setDomainCrosshairValue(double value) { 1367 setDomainCrosshairValue(value, true); 1368 } 1369 1370 /** 1371 * Sets the domain crosshair value. 1372 * <P> 1373 * Registered listeners are notified that the axis has been modified, but 1374 * only if the crosshair is visible. 1375 * 1376 * @param value the new value. 1377 * @param notify a flag that controls whether or not listeners are 1378 * notified. 1379 */ 1380 public void setDomainCrosshairValue(double value, boolean notify) { 1381 this.domainCrosshairValue = value; 1382 if (isDomainCrosshairVisible() && notify) { 1383 notifyListeners(new PlotChangeEvent(this)); 1384 } 1385 } 1386 1387 /** 1388 * Returns the Stroke used to draw the crosshair (if visible). 1389 * 1390 * @return The crosshair stroke. 1391 */ 1392 public Stroke getDomainCrosshairStroke() { 1393 return this.domainCrosshairStroke; 1394 } 1395 1396 /** 1397 * Sets the Stroke used to draw the crosshairs (if visible) and notifies 1398 * registered listeners that the axis has been modified. 1399 * 1400 * @param stroke the new crosshair stroke. 1401 */ 1402 public void setDomainCrosshairStroke(Stroke stroke) { 1403 this.domainCrosshairStroke = stroke; 1404 notifyListeners(new PlotChangeEvent(this)); 1405 } 1406 1407 /** 1408 * Returns the domain crosshair color. 1409 * 1410 * @return The crosshair color. 1411 */ 1412 public Paint getDomainCrosshairPaint() { 1413 return this.domainCrosshairPaint; 1414 } 1415 1416 /** 1417 * Sets the Paint used to color the crosshairs (if visible) and notifies 1418 * registered listeners that the axis has been modified. 1419 * 1420 * @param paint the new crosshair paint. 1421 */ 1422 public void setDomainCrosshairPaint(Paint paint) { 1423 this.domainCrosshairPaint = paint; 1424 notifyListeners(new PlotChangeEvent(this)); 1425 } 1426 1427 /** 1428 * Returns a flag indicating whether or not the range crosshair is visible. 1429 * 1430 * @return The flag. 1431 */ 1432 public boolean isRangeCrosshairVisible() { 1433 return this.rangeCrosshairVisible; 1434 } 1435 1436 /** 1437 * Sets the flag indicating whether or not the range crosshair is visible. 1438 * 1439 * @param flag the new value of the flag. 1440 */ 1441 public void setRangeCrosshairVisible(boolean flag) { 1442 if (this.rangeCrosshairVisible != flag) { 1443 this.rangeCrosshairVisible = flag; 1444 notifyListeners(new PlotChangeEvent(this)); 1445 } 1446 } 1447 1448 /** 1449 * Returns a flag indicating whether or not the crosshair should "lock-on" 1450 * to actual data values. 1451 * 1452 * @return The flag. 1453 */ 1454 public boolean isRangeCrosshairLockedOnData() { 1455 return this.rangeCrosshairLockedOnData; 1456 } 1457 1458 /** 1459 * Sets the flag indicating whether or not the range crosshair should 1460 * "lock-on" to actual data values. 1461 * 1462 * @param flag the flag. 1463 */ 1464 public void setRangeCrosshairLockedOnData(boolean flag) { 1465 if (this.rangeCrosshairLockedOnData != flag) { 1466 this.rangeCrosshairLockedOnData = flag; 1467 notifyListeners(new PlotChangeEvent(this)); 1468 } 1469 } 1470 1471 /** 1472 * Returns the range crosshair value. 1473 * 1474 * @return The value. 1475 */ 1476 public double getRangeCrosshairValue() { 1477 return this.rangeCrosshairValue; 1478 } 1479 1480 /** 1481 * Sets the domain crosshair value. 1482 * <P> 1483 * Registered listeners are notified that the plot has been modified, but 1484 * only if the crosshair is visible. 1485 * 1486 * @param value the new value. 1487 */ 1488 public void setRangeCrosshairValue(double value) { 1489 setRangeCrosshairValue(value, true); 1490 } 1491 1492 /** 1493 * Sets the range crosshair value. 1494 * <P> 1495 * Registered listeners are notified that the axis has been modified, but 1496 * only if the crosshair is visible. 1497 * 1498 * @param value the new value. 1499 * @param notify a flag that controls whether or not listeners are 1500 * notified. 1501 */ 1502 public void setRangeCrosshairValue(double value, boolean notify) { 1503 this.rangeCrosshairValue = value; 1504 if (isRangeCrosshairVisible() && notify) { 1505 notifyListeners(new PlotChangeEvent(this)); 1506 } 1507 } 1508 1509 /** 1510 * Returns the Stroke used to draw the crosshair (if visible). 1511 * 1512 * @return The crosshair stroke. 1513 */ 1514 public Stroke getRangeCrosshairStroke() { 1515 return this.rangeCrosshairStroke; 1516 } 1517 1518 /** 1519 * Sets the Stroke used to draw the crosshairs (if visible) and notifies 1520 * registered listeners that the axis has been modified. 1521 * 1522 * @param stroke the new crosshair stroke. 1523 */ 1524 public void setRangeCrosshairStroke(Stroke stroke) { 1525 this.rangeCrosshairStroke = stroke; 1526 notifyListeners(new PlotChangeEvent(this)); 1527 } 1528 1529 /** 1530 * Returns the range crosshair color. 1531 * 1532 * @return The crosshair color. 1533 */ 1534 public Paint getRangeCrosshairPaint() { 1535 return this.rangeCrosshairPaint; 1536 } 1537 1538 /** 1539 * Sets the Paint used to color the crosshairs (if visible) and notifies 1540 * registered listeners that the axis has been modified. 1541 * 1542 * @param paint the new crosshair paint. 1543 */ 1544 public void setRangeCrosshairPaint(Paint paint) { 1545 this.rangeCrosshairPaint = paint; 1546 notifyListeners(new PlotChangeEvent(this)); 1547 } 1548 1549 /** 1550 * Returns the tool tip generator. 1551 * 1552 * @return The tool tip generator (possibly null). 1553 */ 1554 public ContourToolTipGenerator getToolTipGenerator() { 1555 return this.toolTipGenerator; 1556 } 1557 1558 /** 1559 * Sets the tool tip generator. 1560 * 1561 * @param generator the tool tip generator (null permitted). 1562 */ 1563 public void setToolTipGenerator(ContourToolTipGenerator generator) { 1564 //Object oldValue = this.toolTipGenerator; 1565 this.toolTipGenerator = generator; 1566 } 1567 1568 /** 1569 * Returns the URL generator for HTML image maps. 1570 * 1571 * @return The URL generator (possibly null). 1572 */ 1573 public XYURLGenerator getURLGenerator() { 1574 return this.urlGenerator; 1575 } 1576 1577 /** 1578 * Sets the URL generator for HTML image maps. 1579 * 1580 * @param urlGenerator the URL generator (null permitted). 1581 */ 1582 public void setURLGenerator(XYURLGenerator urlGenerator) { 1583 //Object oldValue = this.urlGenerator; 1584 this.urlGenerator = urlGenerator; 1585 } 1586 1587 /** 1588 * Draws a vertical line on the chart to represent a 'range marker'. 1589 * 1590 * @param g2 the graphics device. 1591 * @param plot the plot. 1592 * @param domainAxis the domain axis. 1593 * @param marker the marker line. 1594 * @param dataArea the axis data area. 1595 */ 1596 public void drawDomainMarker(Graphics2D g2, 1597 ContourPlot plot, 1598 ValueAxis domainAxis, 1599 Marker marker, 1600 Rectangle2D dataArea) { 1601 1602 if (marker instanceof ValueMarker) { 1603 ValueMarker vm = (ValueMarker) marker; 1604 double value = vm.getValue(); 1605 Range range = domainAxis.getRange(); 1606 if (!range.contains(value)) { 1607 return; 1608 } 1609 1610 double x = domainAxis.valueToJava2D(value, dataArea, 1611 RectangleEdge.BOTTOM); 1612 Line2D line = new Line2D.Double(x, dataArea.getMinY(), x, 1613 dataArea.getMaxY()); 1614 Paint paint = marker.getOutlinePaint(); 1615 Stroke stroke = marker.getOutlineStroke(); 1616 g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT); 1617 g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE); 1618 g2.draw(line); 1619 } 1620 1621 } 1622 1623 /** 1624 * Draws a horizontal line across the chart to represent a 'range marker'. 1625 * 1626 * @param g2 the graphics device. 1627 * @param plot the plot. 1628 * @param rangeAxis the range axis. 1629 * @param marker the marker line. 1630 * @param dataArea the axis data area. 1631 */ 1632 public void drawRangeMarker(Graphics2D g2, 1633 ContourPlot plot, 1634 ValueAxis rangeAxis, 1635 Marker marker, 1636 Rectangle2D dataArea) { 1637 1638 if (marker instanceof ValueMarker) { 1639 ValueMarker vm = (ValueMarker) marker; 1640 double value = vm.getValue(); 1641 Range range = rangeAxis.getRange(); 1642 if (!range.contains(value)) { 1643 return; 1644 } 1645 1646 double y = rangeAxis.valueToJava2D(value, dataArea, 1647 RectangleEdge.LEFT); 1648 Line2D line = new Line2D.Double(dataArea.getMinX(), y, 1649 dataArea.getMaxX(), y); 1650 Paint paint = marker.getOutlinePaint(); 1651 Stroke stroke = marker.getOutlineStroke(); 1652 g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT); 1653 g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE); 1654 g2.draw(line); 1655 } 1656 1657 } 1658 1659 /** 1660 * Returns the clipPath. 1661 * @return ClipPath 1662 */ 1663 public ClipPath getClipPath() { 1664 return this.clipPath; 1665 } 1666 1667 /** 1668 * Sets the clipPath. 1669 * @param clipPath The clipPath to set 1670 */ 1671 public void setClipPath(ClipPath clipPath) { 1672 this.clipPath = clipPath; 1673 } 1674 1675 /** 1676 * Returns the ptSizePct. 1677 * @return double 1678 */ 1679 public double getPtSizePct() { 1680 return this.ptSizePct; 1681 } 1682 1683 /** 1684 * Returns the renderAsPoints. 1685 * @return boolean 1686 */ 1687 public boolean isRenderAsPoints() { 1688 return this.renderAsPoints; 1689 } 1690 1691 /** 1692 * Sets the ptSizePct. 1693 * @param ptSizePct The ptSizePct to set 1694 */ 1695 public void setPtSizePct(double ptSizePct) { 1696 this.ptSizePct = ptSizePct; 1697 } 1698 1699 /** 1700 * Sets the renderAsPoints. 1701 * @param renderAsPoints The renderAsPoints to set 1702 */ 1703 public void setRenderAsPoints(boolean renderAsPoints) { 1704 this.renderAsPoints = renderAsPoints; 1705 } 1706 1707 /** 1708 * Receives notification of a change to one of the plot's axes. 1709 * 1710 * @param event information about the event. 1711 */ 1712 public void axisChanged(AxisChangeEvent event) { 1713 Object source = event.getSource(); 1714 if (source.equals(this.rangeAxis) || source.equals(this.domainAxis)) { 1715 ColorBar cba = this.colorBar; 1716 if (this.colorBar.getAxis().isAutoRange()) { 1717 cba.getAxis().configure(); 1718 } 1719 1720 } 1721 super.axisChanged(event); 1722 } 1723 1724 /** 1725 * Returns the visible z-range. 1726 * 1727 * @param data the dataset. 1728 * @param x the x range. 1729 * @param y the y range. 1730 * 1731 * @return The range. 1732 */ 1733 public Range visibleRange(ContourDataset data, Range x, Range y) { 1734 Range range = null; 1735 range = data.getZValueRange(x, y); 1736 return range; 1737 } 1738 1739 /** 1740 * Returns the missingPaint. 1741 * @return Paint 1742 */ 1743 public Paint getMissingPaint() { 1744 return this.missingPaint; 1745 } 1746 1747 /** 1748 * Sets the missingPaint. 1749 * 1750 * @param paint the missingPaint to set. 1751 */ 1752 public void setMissingPaint(Paint paint) { 1753 this.missingPaint = paint; 1754 } 1755 1756 /** 1757 * Multiplies the range on the domain axis/axes by the specified factor 1758 * (to be implemented). 1759 * 1760 * @param x the x-coordinate (in Java2D space). 1761 * @param y the y-coordinate (in Java2D space). 1762 * @param factor the zoom factor. 1763 */ 1764 public void zoomDomainAxes(double x, double y, double factor) { 1765 // TODO: to be implemented 1766 } 1767 1768 /** 1769 * Zooms the domain axes (not yet implemented). 1770 * 1771 * @param x the x-coordinate (in Java2D space). 1772 * @param y the y-coordinate (in Java2D space). 1773 * @param lowerPercent the new lower bound. 1774 * @param upperPercent the new upper bound. 1775 */ 1776 public void zoomDomainAxes(double x, double y, double lowerPercent, 1777 double upperPercent) { 1778 // TODO: to be implemented 1779 } 1780 1781 /** 1782 * Multiplies the range on the range axis/axes by the specified factor. 1783 * 1784 * @param x the x-coordinate (in Java2D space). 1785 * @param y the y-coordinate (in Java2D space). 1786 * @param factor the zoom factor. 1787 */ 1788 public void zoomRangeAxes(double x, double y, double factor) { 1789 // TODO: to be implemented 1790 } 1791 1792 /** 1793 * Zooms the range axes (not yet implemented). 1794 * 1795 * @param x the x-coordinate (in Java2D space). 1796 * @param y the y-coordinate (in Java2D space). 1797 * @param lowerPercent the new lower bound. 1798 * @param upperPercent the new upper bound. 1799 */ 1800 public void zoomRangeAxes(double x, double y, double lowerPercent, 1801 double upperPercent) { 1802 // TODO: to be implemented 1803 } 1804 1805 /** 1806 * Returns <code>false</code>. 1807 * 1808 * @return A boolean. 1809 */ 1810 public boolean isDomainZoomable() { 1811 return false; 1812 } 1813 1814 /** 1815 * Returns <code>false</code>. 1816 * 1817 * @return A boolean. 1818 */ 1819 public boolean isRangeZoomable() { 1820 return false; 1821 } 1822 1823 /** 1824 * Extends plot cloning to this plot type 1825 * @see org.jfree.chart.plot.Plot#clone() 1826 */ 1827 public Object clone() throws CloneNotSupportedException { 1828 ContourPlot clone = (ContourPlot) super.clone(); 1829 1830 if (this.domainAxis != null) { 1831 clone.domainAxis = (ValueAxis) this.domainAxis.clone(); 1832 clone.domainAxis.setPlot(clone); 1833 clone.domainAxis.addChangeListener(clone); 1834 } 1835 if (this.rangeAxis != null) { 1836 clone.rangeAxis = (ValueAxis) this.rangeAxis.clone(); 1837 clone.rangeAxis.setPlot(clone); 1838 clone.rangeAxis.addChangeListener(clone); 1839 } 1840 1841 if (clone.dataset != null) { 1842 clone.dataset.addChangeListener(clone); 1843 } 1844 1845 if (this.colorBar != null) { 1846 clone.colorBar = (ColorBar) this.colorBar.clone(); 1847 } 1848 1849 clone.domainMarkers = (List) ObjectUtilities.deepClone( 1850 this.domainMarkers); 1851 clone.rangeMarkers = (List) ObjectUtilities.deepClone( 1852 this.rangeMarkers); 1853 clone.annotations = (List) ObjectUtilities.deepClone(this.annotations); 1854 1855 if (this.clipPath != null) { 1856 clone.clipPath = (ClipPath) this.clipPath.clone(); 1857 } 1858 1859 return clone; 1860 } 1861 1862 }