1:
69:
70: package ;
71:
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90: import ;
91:
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109: import ;
110: import ;
111: import ;
112: import ;
113:
114:
120: public class ContourPlot extends Plot implements ContourValuePlot,
121: ValueAxisPlot,
122: PropertyChangeListener,
123: Serializable,
124: Cloneable {
125:
126:
127: private static final long serialVersionUID = 7861072556590502247L;
128:
129:
130: protected static final RectangleInsets DEFAULT_INSETS
131: = new RectangleInsets(2.0, 2.0, 100.0, 10.0);
132:
133:
134: private ValueAxis domainAxis;
135:
136:
137: private ValueAxis rangeAxis;
138:
139:
140: private ContourDataset dataset;
141:
142:
143: private ColorBar colorBar = null;
144:
145:
146: private RectangleEdge colorBarLocation;
147:
148:
149: private boolean domainCrosshairVisible;
150:
151:
152: private double domainCrosshairValue;
153:
154:
155: private transient Stroke domainCrosshairStroke;
156:
157:
158: private transient Paint domainCrosshairPaint;
159:
160:
164: private boolean domainCrosshairLockedOnData = true;
165:
166:
167: private boolean rangeCrosshairVisible;
168:
169:
170: private double rangeCrosshairValue;
171:
172:
173: private transient Stroke rangeCrosshairStroke;
174:
175:
176: private transient Paint rangeCrosshairPaint;
177:
178:
182: private boolean rangeCrosshairLockedOnData = true;
183:
184:
193: private double dataAreaRatio = 0.0;
194:
195:
196: private List domainMarkers;
197:
198:
199: private List rangeMarkers;
200:
201:
202: private List annotations;
203:
204:
205: private ContourToolTipGenerator toolTipGenerator;
206:
207:
208: private XYURLGenerator urlGenerator;
209:
210:
214: private boolean renderAsPoints = false;
215:
216:
220: private double ptSizePct = 0.05;
221:
222:
223: private transient ClipPath clipPath = null;
224:
225:
226: private transient Paint missingPaint = null;
227:
228:
229: protected static ResourceBundle localizationResources =
230: ResourceBundle.getBundle("org.jfree.chart.plot.LocalizationBundle");
231:
232:
235: public ContourPlot() {
236: this(null, null, null, null);
237: }
238:
239:
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:
288: public RectangleEdge getColorBarLocation() {
289: return this.colorBarLocation;
290: }
291:
292:
298: public void setColorBarLocation(RectangleEdge edge) {
299: this.colorBarLocation = edge;
300: notifyListeners(new PlotChangeEvent(this));
301: }
302:
303:
308: public ContourDataset getDataset() {
309: return this.dataset;
310: }
311:
312:
318: public void setDataset(ContourDataset dataset) {
319:
320:
321:
322: ContourDataset existing = this.dataset;
323: if (existing != null) {
324: existing.removeChangeListener(this);
325: }
326:
327:
328: this.dataset = dataset;
329: if (dataset != null) {
330: setDatasetGroup(dataset.getGroup());
331: dataset.addChangeListener(this);
332: }
333:
334:
335: DatasetChangeEvent event = new DatasetChangeEvent(this, dataset);
336: datasetChanged(event);
337:
338: }
339:
340:
345: public ValueAxis getDomainAxis() {
346:
347: ValueAxis result = this.domainAxis;
348:
349: return result;
350:
351: }
352:
353:
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:
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:
385: public ValueAxis getRangeAxis() {
386:
387: ValueAxis result = this.rangeAxis;
388:
389: return result;
390:
391: }
392:
393:
401: public void setRangeAxis(ValueAxis axis) {
402:
403: if (axis != null) {
404: axis.setPlot(this);
405: axis.addChangeListener(this);
406: }
407:
408:
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:
423: public void setColorBarAxis(ColorBar axis) {
424:
425: this.colorBar = axis;
426: notifyListeners(new PlotChangeEvent(this));
427:
428: }
429:
430:
435: public double getDataAreaRatio() {
436: return this.dataAreaRatio;
437: }
438:
439:
444: public void setDataAreaRatio(double ratio) {
445: this.dataAreaRatio = ratio;
446: }
447:
448:
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:
469: public void clearDomainMarkers() {
470: if (this.domainMarkers != null) {
471: this.domainMarkers.clear();
472: notifyListeners(new PlotChangeEvent(this));
473: }
474: }
475:
476:
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:
497: public void clearRangeMarkers() {
498: if (this.rangeMarkers != null) {
499: this.rangeMarkers.clear();
500: notifyListeners(new PlotChangeEvent(this));
501: }
502: }
503:
504:
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:
522: public void clearAnnotations() {
523: if (this.annotations != null) {
524: this.annotations.clear();
525: notifyListeners(new PlotChangeEvent(this));
526: }
527: }
528:
529:
537: public boolean isCompatibleDomainAxis(ValueAxis axis) {
538:
539: return true;
540:
541: }
542:
543:
559: public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor,
560: PlotState parentState,
561: PlotRenderingInfo info) {
562:
563:
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:
571: if (info != null) {
572: info.setPlotArea(area);
573: }
574:
575:
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:
598: if (getDataAreaRatio() != 0.0) {
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) {
605: if (w * ratio <= h) {
606: h = ratio * w;
607: }
608: else {
609: w = h / ratio;
610: }
611: }
612: else {
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:
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:
684:
685:
686:
687:
688:
689:
690:
691:
692:
693:
694:
695:
696:
697:
698:
699:
700: g2.setClip(originalClip);
701: g2.setComposite(originalComposite);
702: drawOutline(g2, dataArea);
703:
704: }
705:
706:
718: public void render(Graphics2D g2, Rectangle2D dataArea,
719: PlotRenderingInfo info, CrosshairState crosshairState) {
720:
721:
722:
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:
746: setDomainCrosshairValue(crosshairState.getCrosshairX(), false);
747: if (isDomainCrosshairVisible()) {
748: drawVerticalLine(g2, dataArea,
749: getDomainCrosshairValue(),
750: getDomainCrosshairStroke(),
751: getDomainCrosshairPaint());
752: }
753:
754:
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:
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:
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:
805: Object antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
806: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
807: RenderingHints.VALUE_ANTIALIAS_OFF);
808:
809:
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) {
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:
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:
933: if (entities != null) {
934: String tip = "";
935: if (getToolTipGenerator() != null) {
936: tip = this.toolTipGenerator.generateToolTip(data, k);
937: }
938:
939:
940: String url = null;
941:
942:
943:
944:
945:
946: ContourEntity entity = new ContourEntity(
947: (Rectangle2D.Double) entityArea.clone(), tip, url);
948: entity.setIndex(k);
949: entities.add(entity);
950:
951: }
952:
953:
954: if (plot.isDomainCrosshairLockedOnData()) {
955: if (plot.isRangeCrosshairLockedOnData()) {
956:
957: crosshairState.updateCrosshairPoint(x[k], y[k], transX,
958: transY, PlotOrientation.VERTICAL);
959: }
960: else {
961:
962: crosshairState.updateCrosshairX(transX);
963: }
964: }
965: else {
966: if (plot.isRangeCrosshairLockedOnData()) {
967:
968: crosshairState.updateCrosshairY(transY);
969: }
970: }
971: }
972:
973: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias);
974:
975: return;
976:
977: }
978:
979:
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:
1004: RectangularShape entityArea = null;
1005: EntityCollection entities = null;
1006: if (info != null) {
1007: entities = info.getOwner().getEntityCollection();
1008: }
1009:
1010:
1011:
1012: RectangularShape rect = new Ellipse2D.Double();
1013:
1014:
1015:
1016: Object antiAlias = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
1017: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1018: RenderingHints.VALUE_ANTIALIAS_OFF);
1019:
1020:
1021:
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:
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:
1070:
1071:
1072:
1073:
1074: ContourEntity entity = new ContourEntity(
1075: (RectangularShape) entityArea.clone(), tip, url);
1076: entity.setIndex(k);
1077: entities.add(entity);
1078: }
1079:
1080:
1081: if (plot.isDomainCrosshairLockedOnData()) {
1082: if (plot.isRangeCrosshairLockedOnData()) {
1083:
1084: crosshairState.updateCrosshairPoint(x[k], y[k], transX,
1085: transY, PlotOrientation.VERTICAL);
1086: }
1087: else {
1088:
1089: crosshairState.updateCrosshairX(transX);
1090: }
1091: }
1092: else {
1093: if (plot.isRangeCrosshairLockedOnData()) {
1094:
1095: crosshairState.updateCrosshairY(transY);
1096: }
1097: }
1098: }
1099:
1100:
1101: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, antiAlias);
1102:
1103: return;
1104:
1105: }
1106:
1107:
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:
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:
1159: public void handleClick(int x, int y, PlotRenderingInfo info) {
1160:
1161:
1182: }
1183:
1184:
1189: public void zoom(double percent) {
1190:
1191: if (percent > 0) {
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199: }
1200: else {
1201: getRangeAxis().setAutoRange(true);
1202: getDomainAxis().setAutoRange(true);
1203: }
1204:
1205: }
1206:
1207:
1212: public String getPlotType() {
1213: return localizationResources.getString("Contour_Plot");
1214: }
1215:
1216:
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:
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:
1269: public void propertyChange(PropertyChangeEvent event) {
1270: notifyListeners(new PlotChangeEvent(this));
1271: }
1272:
1273:
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:
1299: public ColorBar getColorBar() {
1300: return this.colorBar;
1301: }
1302:
1303:
1308: public boolean isDomainCrosshairVisible() {
1309: return this.domainCrosshairVisible;
1310: }
1311:
1312:
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:
1332: public boolean isDomainCrosshairLockedOnData() {
1333: return this.domainCrosshairLockedOnData;
1334: }
1335:
1336:
1342: public void setDomainCrosshairLockedOnData(boolean flag) {
1343: if (this.domainCrosshairLockedOnData != flag) {
1344: this.domainCrosshairLockedOnData = flag;
1345: notifyListeners(new PlotChangeEvent(this));
1346: }
1347: }
1348:
1349:
1354: public double getDomainCrosshairValue() {
1355: return this.domainCrosshairValue;
1356: }
1357:
1358:
1366: public void setDomainCrosshairValue(double value) {
1367: setDomainCrosshairValue(value, true);
1368: }
1369:
1370:
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:
1392: public Stroke getDomainCrosshairStroke() {
1393: return this.domainCrosshairStroke;
1394: }
1395:
1396:
1402: public void setDomainCrosshairStroke(Stroke stroke) {
1403: this.domainCrosshairStroke = stroke;
1404: notifyListeners(new PlotChangeEvent(this));
1405: }
1406:
1407:
1412: public Paint getDomainCrosshairPaint() {
1413: return this.domainCrosshairPaint;
1414: }
1415:
1416:
1422: public void setDomainCrosshairPaint(Paint paint) {
1423: this.domainCrosshairPaint = paint;
1424: notifyListeners(new PlotChangeEvent(this));
1425: }
1426:
1427:
1432: public boolean isRangeCrosshairVisible() {
1433: return this.rangeCrosshairVisible;
1434: }
1435:
1436:
1441: public void setRangeCrosshairVisible(boolean flag) {
1442: if (this.rangeCrosshairVisible != flag) {
1443: this.rangeCrosshairVisible = flag;
1444: notifyListeners(new PlotChangeEvent(this));
1445: }
1446: }
1447:
1448:
1454: public boolean isRangeCrosshairLockedOnData() {
1455: return this.rangeCrosshairLockedOnData;
1456: }
1457:
1458:
1464: public void setRangeCrosshairLockedOnData(boolean flag) {
1465: if (this.rangeCrosshairLockedOnData != flag) {
1466: this.rangeCrosshairLockedOnData = flag;
1467: notifyListeners(new PlotChangeEvent(this));
1468: }
1469: }
1470:
1471:
1476: public double getRangeCrosshairValue() {
1477: return this.rangeCrosshairValue;
1478: }
1479:
1480:
1488: public void setRangeCrosshairValue(double value) {
1489: setRangeCrosshairValue(value, true);
1490: }
1491:
1492:
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:
1514: public Stroke getRangeCrosshairStroke() {
1515: return this.rangeCrosshairStroke;
1516: }
1517:
1518:
1524: public void setRangeCrosshairStroke(Stroke stroke) {
1525: this.rangeCrosshairStroke = stroke;
1526: notifyListeners(new PlotChangeEvent(this));
1527: }
1528:
1529:
1534: public Paint getRangeCrosshairPaint() {
1535: return this.rangeCrosshairPaint;
1536: }
1537:
1538:
1544: public void setRangeCrosshairPaint(Paint paint) {
1545: this.rangeCrosshairPaint = paint;
1546: notifyListeners(new PlotChangeEvent(this));
1547: }
1548:
1549:
1554: public ContourToolTipGenerator getToolTipGenerator() {
1555: return this.toolTipGenerator;
1556: }
1557:
1558:
1563: public void setToolTipGenerator(ContourToolTipGenerator generator) {
1564:
1565: this.toolTipGenerator = generator;
1566: }
1567:
1568:
1573: public XYURLGenerator getURLGenerator() {
1574: return this.urlGenerator;
1575: }
1576:
1577:
1582: public void setURLGenerator(XYURLGenerator urlGenerator) {
1583:
1584: this.urlGenerator = urlGenerator;
1585: }
1586:
1587:
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:
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:
1663: public ClipPath getClipPath() {
1664: return this.clipPath;
1665: }
1666:
1667:
1671: public void setClipPath(ClipPath clipPath) {
1672: this.clipPath = clipPath;
1673: }
1674:
1675:
1679: public double getPtSizePct() {
1680: return this.ptSizePct;
1681: }
1682:
1683:
1687: public boolean isRenderAsPoints() {
1688: return this.renderAsPoints;
1689: }
1690:
1691:
1695: public void setPtSizePct(double ptSizePct) {
1696: this.ptSizePct = ptSizePct;
1697: }
1698:
1699:
1703: public void setRenderAsPoints(boolean renderAsPoints) {
1704: this.renderAsPoints = renderAsPoints;
1705: }
1706:
1707:
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:
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:
1743: public Paint getMissingPaint() {
1744: return this.missingPaint;
1745: }
1746:
1747:
1752: public void setMissingPaint(Paint paint) {
1753: this.missingPaint = paint;
1754: }
1755:
1756:
1764: public void zoomDomainAxes(double x, double y, double factor) {
1765:
1766: }
1767:
1768:
1776: public void zoomDomainAxes(double x, double y, double lowerPercent,
1777: double upperPercent) {
1778:
1779: }
1780:
1781:
1788: public void zoomRangeAxes(double x, double y, double factor) {
1789:
1790: }
1791:
1792:
1800: public void zoomRangeAxes(double x, double y, double lowerPercent,
1801: double upperPercent) {
1802:
1803: }
1804:
1805:
1810: public boolean isDomainZoomable() {
1811: return false;
1812: }
1813:
1814:
1819: public boolean isRangeZoomable() {
1820: return false;
1821: }
1822:
1823:
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: }