1:
75:
76: package ;
77:
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: import ;
92:
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:
111:
115: public class XYDifferenceRenderer extends AbstractXYItemRenderer
116: implements XYItemRenderer,
117: Cloneable,
118: PublicCloneable,
119: Serializable {
120:
121:
122: private static final long serialVersionUID = -8447915602375584857L;
123:
124:
125: private transient Paint positivePaint;
126:
127:
128: private transient Paint negativePaint;
129:
130:
131: private boolean shapesVisible;
132:
133:
134: private transient Shape legendLine;
135:
136:
145: private boolean roundXCoordinates;
146:
147:
150: public XYDifferenceRenderer() {
151: this(Color.green, Color.red, false);
152: }
153:
154:
163: public XYDifferenceRenderer(Paint positivePaint, Paint negativePaint,
164: boolean shapes) {
165: if (positivePaint == null) {
166: throw new IllegalArgumentException(
167: "Null 'positivePaint' argument.");
168: }
169: if (negativePaint == null) {
170: throw new IllegalArgumentException(
171: "Null 'negativePaint' argument.");
172: }
173: this.positivePaint = positivePaint;
174: this.negativePaint = negativePaint;
175: this.shapesVisible = shapes;
176: this.legendLine = new Line2D.Double(-7.0, 0.0, 7.0, 0.0);
177: this.roundXCoordinates = false;
178: }
179:
180:
187: public Paint getPositivePaint() {
188: return this.positivePaint;
189: }
190:
191:
199: public void setPositivePaint(Paint paint) {
200: if (paint == null) {
201: throw new IllegalArgumentException("Null 'paint' argument.");
202: }
203: this.positivePaint = paint;
204: fireChangeEvent();
205: }
206:
207:
214: public Paint getNegativePaint() {
215: return this.negativePaint;
216: }
217:
218:
225: public void setNegativePaint(Paint paint) {
226: if (paint == null) {
227: throw new IllegalArgumentException("Null 'paint' argument.");
228: }
229: this.negativePaint = paint;
230: notifyListeners(new RendererChangeEvent(this));
231: }
232:
233:
241: public boolean getShapesVisible() {
242: return this.shapesVisible;
243: }
244:
245:
254: public void setShapesVisible(boolean flag) {
255: this.shapesVisible = flag;
256: fireChangeEvent();
257: }
258:
259:
266: public Shape getLegendLine() {
267: return this.legendLine;
268: }
269:
270:
278: public void setLegendLine(Shape line) {
279: if (line == null) {
280: throw new IllegalArgumentException("Null 'line' argument.");
281: }
282: this.legendLine = line;
283: fireChangeEvent();
284: }
285:
286:
296: public boolean getRoundXCoordinates() {
297: return this.roundXCoordinates;
298: }
299:
300:
311: public void setRoundXCoordinates(boolean round) {
312: this.roundXCoordinates = round;
313: fireChangeEvent();
314: }
315:
316:
332: public XYItemRendererState initialise(Graphics2D g2,
333: Rectangle2D dataArea,
334: XYPlot plot,
335: XYDataset data,
336: PlotRenderingInfo info) {
337:
338: XYItemRendererState state = super.initialise(g2, dataArea, plot, data,
339: info);
340: state.setProcessVisibleItemsOnly(false);
341: return state;
342:
343: }
344:
345:
351: public int getPassCount() {
352: return 2;
353: }
354:
355:
373: public void drawItem(Graphics2D g2,
374: XYItemRendererState state,
375: Rectangle2D dataArea,
376: PlotRenderingInfo info,
377: XYPlot plot,
378: ValueAxis domainAxis,
379: ValueAxis rangeAxis,
380: XYDataset dataset,
381: int series,
382: int item,
383: CrosshairState crosshairState,
384: int pass) {
385:
386: if (pass == 0) {
387: drawItemPass0(g2, dataArea, info, plot, domainAxis, rangeAxis,
388: dataset, series, item, crosshairState);
389: }
390: else if (pass == 1) {
391: drawItemPass1(g2, dataArea, info, plot, domainAxis, rangeAxis,
392: dataset, series, item, crosshairState);
393: }
394:
395: }
396:
397:
413: protected void drawItemPass0(Graphics2D x_graphics,
414: Rectangle2D x_dataArea,
415: PlotRenderingInfo x_info,
416: XYPlot x_plot,
417: ValueAxis x_domainAxis,
418: ValueAxis x_rangeAxis,
419: XYDataset x_dataset,
420: int x_series,
421: int x_item,
422: CrosshairState x_crosshairState) {
423:
424: if (!((0 == x_series) && (0 == x_item))) {
425: return;
426: }
427:
428: boolean b_impliedZeroSubtrahend = (1 == x_dataset.getSeriesCount());
429:
430:
431: if (isEitherSeriesDegenerate(x_dataset, b_impliedZeroSubtrahend)) {
432: return;
433: }
434:
435:
436: if (!b_impliedZeroSubtrahend && areSeriesDisjoint(x_dataset)) {
437: return;
438: }
439:
440:
441: LinkedList l_minuendXs = new LinkedList();
442: LinkedList l_minuendYs = new LinkedList();
443: LinkedList l_subtrahendXs = new LinkedList();
444: LinkedList l_subtrahendYs = new LinkedList();
445: LinkedList l_polygonXs = new LinkedList();
446: LinkedList l_polygonYs = new LinkedList();
447:
448:
449: int l_minuendItem = 0;
450: int l_minuendItemCount = x_dataset.getItemCount(0);
451: Double l_minuendCurX = null;
452: Double l_minuendNextX = null;
453: Double l_minuendCurY = null;
454: Double l_minuendNextY = null;
455: double l_minuendMaxY = Double.NEGATIVE_INFINITY;
456: double l_minuendMinY = Double.POSITIVE_INFINITY;
457:
458: int l_subtrahendItem = 0;
459: int l_subtrahendItemCount = 0;
460: Double l_subtrahendCurX = null;
461: Double l_subtrahendNextX = null;
462: Double l_subtrahendCurY = null;
463: Double l_subtrahendNextY = null;
464: double l_subtrahendMaxY = Double.NEGATIVE_INFINITY;
465: double l_subtrahendMinY = Double.POSITIVE_INFINITY;
466:
467:
468: if (b_impliedZeroSubtrahend) {
469: l_subtrahendItem = 0;
470: l_subtrahendItemCount = 2;
471: l_subtrahendCurX = new Double(x_dataset.getXValue(0, 0));
472: l_subtrahendNextX = new Double(x_dataset.getXValue(0,
473: (l_minuendItemCount - 1)));
474: l_subtrahendCurY = new Double(0.0);
475: l_subtrahendNextY = new Double(0.0);
476: l_subtrahendMaxY = 0.0;
477: l_subtrahendMinY = 0.0;
478:
479: l_subtrahendXs.add(l_subtrahendCurX);
480: l_subtrahendYs.add(l_subtrahendCurY);
481: }
482: else {
483: l_subtrahendItemCount = x_dataset.getItemCount(1);
484: }
485:
486: boolean b_minuendDone = false;
487: boolean b_minuendAdvanced = true;
488: boolean b_minuendAtIntersect = false;
489: boolean b_minuendFastForward = false;
490: boolean b_subtrahendDone = false;
491: boolean b_subtrahendAdvanced = true;
492: boolean b_subtrahendAtIntersect = false;
493: boolean b_subtrahendFastForward = false;
494: boolean b_colinear = false;
495:
496: boolean b_positive;
497:
498:
499: double l_x1 = 0.0, l_y1 = 0.0;
500: double l_x2 = 0.0, l_y2 = 0.0;
501: double l_x3 = 0.0, l_y3 = 0.0;
502: double l_x4 = 0.0, l_y4 = 0.0;
503:
504:
505: boolean b_fastForwardDone = false;
506: while (!b_fastForwardDone) {
507:
508: l_x1 = x_dataset.getXValue(0, l_minuendItem);
509: l_y1 = x_dataset.getYValue(0, l_minuendItem);
510: l_x2 = x_dataset.getXValue(0, l_minuendItem + 1);
511: l_y2 = x_dataset.getYValue(0, l_minuendItem + 1);
512:
513: l_minuendCurX = new Double(l_x1);
514: l_minuendCurY = new Double(l_y1);
515: l_minuendNextX = new Double(l_x2);
516: l_minuendNextY = new Double(l_y2);
517:
518: if (b_impliedZeroSubtrahend) {
519: l_x3 = l_subtrahendCurX.doubleValue();
520: l_y3 = l_subtrahendCurY.doubleValue();
521: l_x4 = l_subtrahendNextX.doubleValue();
522: l_y4 = l_subtrahendNextY.doubleValue();
523: }
524: else {
525: l_x3 = x_dataset.getXValue(1, l_subtrahendItem);
526: l_y3 = x_dataset.getYValue(1, l_subtrahendItem);
527: l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1);
528: l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1);
529:
530: l_subtrahendCurX = new Double(l_x3);
531: l_subtrahendCurY = new Double(l_y3);
532: l_subtrahendNextX = new Double(l_x4);
533: l_subtrahendNextY = new Double(l_y4);
534: }
535:
536: if (l_x2 <= l_x3) {
537:
538: l_minuendItem++;
539: b_minuendFastForward = true;
540: continue;
541: }
542:
543: if (l_x4 <= l_x1) {
544:
545: l_subtrahendItem++;
546: b_subtrahendFastForward = true;
547: continue;
548: }
549:
550:
551: if ((l_x3 < l_x1) && (l_x1 < l_x4)) {
552:
553: double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3);
554: l_subtrahendCurX = l_minuendCurX;
555: l_subtrahendCurY = new Double((l_slope * l_x1)
556: + (l_y3 - (l_slope * l_x3)));
557:
558: l_subtrahendXs.add(l_subtrahendCurX);
559: l_subtrahendYs.add(l_subtrahendCurY);
560: }
561:
562: if ((l_x1 < l_x3) && (l_x3 < l_x2)) {
563:
564: double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1);
565: l_minuendCurX = l_subtrahendCurX;
566: l_minuendCurY = new Double((l_slope * l_x3)
567: + (l_y1 - (l_slope * l_x1)));
568:
569: l_minuendXs.add(l_minuendCurX);
570: l_minuendYs.add(l_minuendCurY);
571: }
572:
573: l_minuendMaxY = l_minuendCurY.doubleValue();
574: l_minuendMinY = l_minuendCurY.doubleValue();
575: l_subtrahendMaxY = l_subtrahendCurY.doubleValue();
576: l_subtrahendMinY = l_subtrahendCurY.doubleValue();
577:
578: b_fastForwardDone = true;
579: }
580:
581:
582: while (!b_minuendDone && !b_subtrahendDone) {
583: if (!b_minuendDone && !b_minuendFastForward && b_minuendAdvanced) {
584: l_x1 = x_dataset.getXValue(0, l_minuendItem);
585: l_y1 = x_dataset.getYValue(0, l_minuendItem);
586: l_minuendCurX = new Double(l_x1);
587: l_minuendCurY = new Double(l_y1);
588:
589: if (!b_minuendAtIntersect) {
590: l_minuendXs.add(l_minuendCurX);
591: l_minuendYs.add(l_minuendCurY);
592: }
593:
594: l_minuendMaxY = Math.max(l_minuendMaxY, l_y1);
595: l_minuendMinY = Math.min(l_minuendMinY, l_y1);
596:
597: l_x2 = x_dataset.getXValue(0, l_minuendItem + 1);
598: l_y2 = x_dataset.getYValue(0, l_minuendItem + 1);
599: l_minuendNextX = new Double(l_x2);
600: l_minuendNextY = new Double(l_y2);
601: }
602:
603:
604: if (!b_impliedZeroSubtrahend && !b_subtrahendDone
605: && !b_subtrahendFastForward && b_subtrahendAdvanced) {
606: l_x3 = x_dataset.getXValue(1, l_subtrahendItem);
607: l_y3 = x_dataset.getYValue(1, l_subtrahendItem);
608: l_subtrahendCurX = new Double(l_x3);
609: l_subtrahendCurY = new Double(l_y3);
610:
611: if (!b_subtrahendAtIntersect) {
612: l_subtrahendXs.add(l_subtrahendCurX);
613: l_subtrahendYs.add(l_subtrahendCurY);
614: }
615:
616: l_subtrahendMaxY = Math.max(l_subtrahendMaxY, l_y3);
617: l_subtrahendMinY = Math.min(l_subtrahendMinY, l_y3);
618:
619: l_x4 = x_dataset.getXValue(1, l_subtrahendItem + 1);
620: l_y4 = x_dataset.getYValue(1, l_subtrahendItem + 1);
621: l_subtrahendNextX = new Double(l_x4);
622: l_subtrahendNextY = new Double(l_y4);
623: }
624:
625:
626: b_minuendFastForward = false;
627: b_subtrahendFastForward = false;
628:
629: Double l_intersectX = null;
630: Double l_intersectY = null;
631: boolean b_intersect = false;
632:
633: b_minuendAtIntersect = false;
634: b_subtrahendAtIntersect = false;
635:
636:
637: if ((l_x2 == l_x4) && (l_y2 == l_y4)) {
638:
639: if ((l_x1 == l_x3) && (l_y1 == l_y3)) {
640: b_colinear = true;
641: }
642: else {
643:
644:
645: l_intersectX = new Double(l_x2);
646: l_intersectY = new Double(l_y2);
647:
648: b_intersect = true;
649: b_minuendAtIntersect = true;
650: b_subtrahendAtIntersect = true;
651: }
652: }
653: else {
654:
655: double l_denominator = ((l_y4 - l_y3) * (l_x2 - l_x1))
656: - ((l_x4 - l_x3) * (l_y2 - l_y1));
657:
658:
659: double l_deltaY = l_y1 - l_y3;
660: double l_deltaX = l_x1 - l_x3;
661:
662:
663: double l_numeratorA = ((l_x4 - l_x3) * l_deltaY)
664: - ((l_y4 - l_y3) * l_deltaX);
665: double l_numeratorB = ((l_x2 - l_x1) * l_deltaY)
666: - ((l_y2 - l_y1) * l_deltaX);
667:
668:
669: if ((0 == l_numeratorA) && (0 == l_numeratorB)
670: && (0 == l_denominator)) {
671: b_colinear = true;
672: }
673: else {
674:
675: if (b_colinear) {
676:
677: l_minuendXs.clear();
678: l_minuendYs.clear();
679: l_subtrahendXs.clear();
680: l_subtrahendYs.clear();
681: l_polygonXs.clear();
682: l_polygonYs.clear();
683:
684: b_colinear = false;
685:
686:
687: boolean b_useMinuend = ((l_x3 <= l_x1)
688: && (l_x1 <= l_x4));
689: l_polygonXs.add(b_useMinuend ? l_minuendCurX
690: : l_subtrahendCurX);
691: l_polygonYs.add(b_useMinuend ? l_minuendCurY
692: : l_subtrahendCurY);
693: }
694:
695:
696: double l_slopeA = l_numeratorA / l_denominator;
697: double l_slopeB = l_numeratorB / l_denominator;
698:
699:
700: if ((0 < l_slopeA) && (l_slopeA <= 1) && (0 < l_slopeB)
701: && (l_slopeB <= 1)) {
702:
703: double l_xi = l_x1 + (l_slopeA * (l_x2 - l_x1));
704: double l_yi = l_y1 + (l_slopeA * (l_y2 - l_y1));
705:
706: l_intersectX = new Double(l_xi);
707: l_intersectY = new Double(l_yi);
708: b_intersect = true;
709: b_minuendAtIntersect = ((l_xi == l_x2)
710: && (l_yi == l_y2));
711: b_subtrahendAtIntersect = ((l_xi == l_x4)
712: && (l_yi == l_y4));
713:
714:
715: l_minuendCurX = l_intersectX;
716: l_minuendCurY = l_intersectY;
717: l_subtrahendCurX = l_intersectX;
718: l_subtrahendCurY = l_intersectY;
719: }
720: }
721: }
722:
723: if (b_intersect) {
724:
725:
726: l_polygonXs.addAll(l_minuendXs);
727: l_polygonYs.addAll(l_minuendYs);
728:
729:
730: l_polygonXs.add(l_intersectX);
731: l_polygonYs.add(l_intersectY);
732:
733:
734: Collections.reverse(l_subtrahendXs);
735: Collections.reverse(l_subtrahendYs);
736: l_polygonXs.addAll(l_subtrahendXs);
737: l_polygonYs.addAll(l_subtrahendYs);
738:
739:
740: b_positive = (l_subtrahendMaxY <= l_minuendMaxY)
741: && (l_subtrahendMinY <= l_minuendMinY);
742: createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis,
743: x_rangeAxis, b_positive, l_polygonXs, l_polygonYs);
744:
745:
746: l_minuendXs.clear();
747: l_minuendYs.clear();
748: l_subtrahendXs.clear();
749: l_subtrahendYs.clear();
750: l_polygonXs.clear();
751: l_polygonYs.clear();
752:
753:
754: double l_y = l_intersectY.doubleValue();
755: l_minuendMaxY = l_y;
756: l_subtrahendMaxY = l_y;
757: l_minuendMinY = l_y;
758: l_subtrahendMinY = l_y;
759:
760:
761: l_polygonXs.add(l_intersectX);
762: l_polygonYs.add(l_intersectY);
763: }
764:
765:
766: if (l_x2 <= l_x4) {
767: l_minuendItem++;
768: b_minuendAdvanced = true;
769: }
770: else {
771: b_minuendAdvanced = false;
772: }
773:
774:
775: if (l_x4 <= l_x2) {
776: l_subtrahendItem++;
777: b_subtrahendAdvanced = true;
778: }
779: else {
780: b_subtrahendAdvanced = false;
781: }
782:
783: b_minuendDone = (l_minuendItem == (l_minuendItemCount - 1));
784: b_subtrahendDone = (l_subtrahendItem == (l_subtrahendItemCount
785: - 1));
786: }
787:
788:
789: if (b_minuendDone && (l_x3 < l_x2) && (l_x2 < l_x4)) {
790:
791: double l_slope = (l_y4 - l_y3) / (l_x4 - l_x3);
792: l_subtrahendNextX = l_minuendNextX;
793: l_subtrahendNextY = new Double((l_slope * l_x2)
794: + (l_y3 - (l_slope * l_x3)));
795: }
796:
797: if (b_subtrahendDone && (l_x1 < l_x4) && (l_x4 < l_x2)) {
798:
799: double l_slope = (l_y2 - l_y1) / (l_x2 - l_x1);
800: l_minuendNextX = l_subtrahendNextX;
801: l_minuendNextY = new Double((l_slope * l_x4)
802: + (l_y1 - (l_slope * l_x1)));
803: }
804:
805:
806:
807: l_minuendMaxY = Math.max(l_minuendMaxY,
808: l_minuendNextY.doubleValue());
809: l_subtrahendMaxY = Math.max(l_subtrahendMaxY,
810: l_subtrahendNextY.doubleValue());
811: l_minuendMinY = Math.min(l_minuendMinY,
812: l_minuendNextY.doubleValue());
813: l_subtrahendMinY = Math.min(l_subtrahendMinY,
814: l_subtrahendNextY.doubleValue());
815:
816:
817: l_minuendXs.add(l_minuendNextX);
818: l_minuendYs.add(l_minuendNextY);
819: l_subtrahendXs.add(l_subtrahendNextX);
820: l_subtrahendYs.add(l_subtrahendNextY);
821:
822:
823:
824: l_polygonXs.addAll(l_minuendXs);
825: l_polygonYs.addAll(l_minuendYs);
826:
827:
828: Collections.reverse(l_subtrahendXs);
829: Collections.reverse(l_subtrahendYs);
830: l_polygonXs.addAll(l_subtrahendXs);
831: l_polygonYs.addAll(l_subtrahendYs);
832:
833:
834: b_positive = (l_subtrahendMaxY <= l_minuendMaxY)
835: && (l_subtrahendMinY <= l_minuendMinY);
836: createPolygon(x_graphics, x_dataArea, x_plot, x_domainAxis,
837: x_rangeAxis, b_positive, l_polygonXs, l_polygonYs);
838: }
839:
840:
858: protected void drawItemPass1(Graphics2D x_graphics,
859: Rectangle2D x_dataArea,
860: PlotRenderingInfo x_info,
861: XYPlot x_plot,
862: ValueAxis x_domainAxis,
863: ValueAxis x_rangeAxis,
864: XYDataset x_dataset,
865: int x_series,
866: int x_item,
867: CrosshairState x_crosshairState) {
868:
869: Shape l_entityArea = null;
870: EntityCollection l_entities = null;
871: if (null != x_info) {
872: l_entities = x_info.getOwner().getEntityCollection();
873: }
874:
875: Paint l_seriesPaint = getItemPaint(x_series, x_item);
876: Stroke l_seriesStroke = getItemStroke(x_series, x_item);
877: x_graphics.setPaint(l_seriesPaint);
878: x_graphics.setStroke(l_seriesStroke);
879:
880: PlotOrientation l_orientation = x_plot.getOrientation();
881: RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge();
882: RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge();
883:
884: double l_x0 = x_dataset.getXValue(x_series, x_item);
885: double l_y0 = x_dataset.getYValue(x_series, x_item);
886: double l_x1 = x_domainAxis.valueToJava2D(l_x0, x_dataArea,
887: l_domainAxisLocation);
888: double l_y1 = x_rangeAxis.valueToJava2D(l_y0, x_dataArea,
889: l_rangeAxisLocation);
890:
891: if (getShapesVisible()) {
892: Shape l_shape = getItemShape(x_series, x_item);
893: if (l_orientation == PlotOrientation.HORIZONTAL) {
894: l_shape = ShapeUtilities.createTranslatedShape(l_shape,
895: l_y1, l_x1);
896: }
897: else {
898: l_shape = ShapeUtilities.createTranslatedShape(l_shape,
899: l_x1, l_y1);
900: }
901: if (l_shape.intersects(x_dataArea)) {
902: x_graphics.setPaint(getItemPaint(x_series, x_item));
903: x_graphics.fill(l_shape);
904: }
905: l_entityArea = l_shape;
906: }
907:
908:
909: if (null != l_entities) {
910: if (null == l_entityArea) {
911: l_entityArea = new Rectangle2D.Double((l_x1 - 2), (l_y1 - 2),
912: 4, 4);
913: }
914: String l_tip = null;
915: XYToolTipGenerator l_tipGenerator = getToolTipGenerator(x_series,
916: x_item);
917: if (null != l_tipGenerator) {
918: l_tip = l_tipGenerator.generateToolTip(x_dataset, x_series,
919: x_item);
920: }
921: String l_url = null;
922: XYURLGenerator l_urlGenerator = getURLGenerator();
923: if (null != l_urlGenerator) {
924: l_url = l_urlGenerator.generateURL(x_dataset, x_series,
925: x_item);
926: }
927: XYItemEntity l_entity = new XYItemEntity(l_entityArea, x_dataset,
928: x_series, x_item, l_tip, l_url);
929: l_entities.add(l_entity);
930: }
931:
932:
933: if (isItemLabelVisible(x_series, x_item)) {
934: drawItemLabel(x_graphics, l_orientation, x_dataset, x_series,
935: x_item, l_x1, l_y1, (l_y1 < 0.0));
936: }
937:
938: int l_domainAxisIndex = x_plot.getDomainAxisIndex(x_domainAxis);
939: int l_rangeAxisIndex = x_plot.getRangeAxisIndex(x_rangeAxis);
940: updateCrosshairValues(x_crosshairState, l_x0, l_y0, l_domainAxisIndex,
941: l_rangeAxisIndex, l_x1, l_y1, l_orientation);
942:
943: if (0 == x_item) {
944: return;
945: }
946:
947: double l_x2 = x_domainAxis.valueToJava2D(x_dataset.getXValue(x_series,
948: (x_item - 1)), x_dataArea, l_domainAxisLocation);
949: double l_y2 = x_rangeAxis.valueToJava2D(x_dataset.getYValue(x_series,
950: (x_item - 1)), x_dataArea, l_rangeAxisLocation);
951:
952: Line2D l_line = null;
953: if (PlotOrientation.HORIZONTAL == l_orientation) {
954: l_line = new Line2D.Double(l_y1, l_x1, l_y2, l_x2);
955: }
956: else if (PlotOrientation.VERTICAL == l_orientation) {
957: l_line = new Line2D.Double(l_x1, l_y1, l_x2, l_y2);
958: }
959:
960: if ((null != l_line) && l_line.intersects(x_dataArea)) {
961: x_graphics.setPaint(getItemPaint(x_series, x_item));
962: x_graphics.setStroke(getItemStroke(x_series, x_item));
963: x_graphics.draw(l_line);
964: }
965: }
966:
967:
976: private boolean isEitherSeriesDegenerate(XYDataset x_dataset,
977: boolean x_impliedZeroSubtrahend) {
978:
979: if (x_impliedZeroSubtrahend) {
980: return (x_dataset.getItemCount(0) < 2);
981: }
982:
983: return ((x_dataset.getItemCount(0) < 2)
984: || (x_dataset.getItemCount(1) < 2));
985: }
986:
987:
995: private boolean areSeriesDisjoint(XYDataset x_dataset) {
996:
997: int l_minuendItemCount = x_dataset.getItemCount(0);
998: double l_minuendFirst = x_dataset.getXValue(0, 0);
999: double l_minuendLast = x_dataset.getXValue(0, l_minuendItemCount - 1);
1000:
1001: int l_subtrahendItemCount = x_dataset.getItemCount(1);
1002: double l_subtrahendFirst = x_dataset.getXValue(1, 0);
1003: double l_subtrahendLast = x_dataset.getXValue(1,
1004: l_subtrahendItemCount - 1);
1005:
1006: return ((l_minuendLast < l_subtrahendFirst)
1007: || (l_subtrahendLast < l_minuendFirst));
1008: }
1009:
1010:
1026: private void createPolygon (Graphics2D x_graphics,
1027: Rectangle2D x_dataArea,
1028: XYPlot x_plot,
1029: ValueAxis x_domainAxis,
1030: ValueAxis x_rangeAxis,
1031: boolean x_positive,
1032: LinkedList x_xValues,
1033: LinkedList x_yValues) {
1034:
1035: PlotOrientation l_orientation = x_plot.getOrientation();
1036: RectangleEdge l_domainAxisLocation = x_plot.getDomainAxisEdge();
1037: RectangleEdge l_rangeAxisLocation = x_plot.getRangeAxisEdge();
1038:
1039: Object[] l_xValues = x_xValues.toArray();
1040: Object[] l_yValues = x_yValues.toArray();
1041:
1042: GeneralPath l_path = new GeneralPath();
1043:
1044: if (PlotOrientation.VERTICAL == l_orientation) {
1045: double l_x = x_domainAxis.valueToJava2D((
1046: (Double) l_xValues[0]).doubleValue(), x_dataArea,
1047: l_domainAxisLocation);
1048: if (this.roundXCoordinates) {
1049: l_x = Math.rint(l_x);
1050: }
1051:
1052: double l_y = x_rangeAxis.valueToJava2D((
1053: (Double) l_yValues[0]).doubleValue(), x_dataArea,
1054: l_rangeAxisLocation);
1055:
1056: l_path.moveTo((float) l_x, (float) l_y);
1057: for (int i = 1; i < l_xValues.length; i++) {
1058: l_x = x_domainAxis.valueToJava2D((
1059: (Double) l_xValues[i]).doubleValue(), x_dataArea,
1060: l_domainAxisLocation);
1061: if (this.roundXCoordinates) {
1062: l_x = Math.rint(l_x);
1063: }
1064:
1065: l_y = x_rangeAxis.valueToJava2D((
1066: (Double) l_yValues[i]).doubleValue(), x_dataArea,
1067: l_rangeAxisLocation);
1068: l_path.lineTo((float) l_x, (float) l_y);
1069: }
1070: l_path.closePath();
1071: }
1072: else {
1073: double l_x = x_domainAxis.valueToJava2D((
1074: (Double) l_xValues[0]).doubleValue(), x_dataArea,
1075: l_domainAxisLocation);
1076: if (this.roundXCoordinates) {
1077: l_x = Math.rint(l_x);
1078: }
1079:
1080: double l_y = x_rangeAxis.valueToJava2D((
1081: (Double) l_yValues[0]).doubleValue(), x_dataArea,
1082: l_rangeAxisLocation);
1083:
1084: l_path.moveTo((float) l_y, (float) l_x);
1085: for (int i = 1; i < l_xValues.length; i++) {
1086: l_x = x_domainAxis.valueToJava2D((
1087: (Double) l_xValues[i]).doubleValue(), x_dataArea,
1088: l_domainAxisLocation);
1089: if (this.roundXCoordinates) {
1090: l_x = Math.rint(l_x);
1091: }
1092:
1093: l_y = x_rangeAxis.valueToJava2D((
1094: (Double) l_yValues[i]).doubleValue(), x_dataArea,
1095: l_rangeAxisLocation);
1096: l_path.lineTo((float) l_y, (float) l_x);
1097: }
1098: l_path.closePath();
1099: }
1100:
1101: if (l_path.intersects(x_dataArea)) {
1102: x_graphics.setPaint(x_positive ? getPositivePaint()
1103: : getNegativePaint());
1104: x_graphics.fill(l_path);
1105: }
1106: }
1107:
1108:
1117: public LegendItem getLegendItem(int datasetIndex, int series) {
1118: LegendItem result = null;
1119: XYPlot p = getPlot();
1120: if (p != null) {
1121: XYDataset dataset = p.getDataset(datasetIndex);
1122: if (dataset != null) {
1123: if (getItemVisible(series, 0)) {
1124: String label = getLegendItemLabelGenerator().generateLabel(
1125: dataset, series);
1126: String description = label;
1127: String toolTipText = null;
1128: if (getLegendItemToolTipGenerator() != null) {
1129: toolTipText
1130: = getLegendItemToolTipGenerator().generateLabel(
1131: dataset, series);
1132: }
1133: String urlText = null;
1134: if (getLegendItemURLGenerator() != null) {
1135: urlText = getLegendItemURLGenerator().generateLabel(
1136: dataset, series);
1137: }
1138: Paint paint = lookupSeriesPaint(series);
1139: Stroke stroke = lookupSeriesStroke(series);
1140:
1141: Line2D line = new Line2D.Double(-7.0, 0.0, 7.0, 0.0);
1142: result = new LegendItem(label, description,
1143: toolTipText, urlText, line, stroke, paint);
1144: result.setDataset(dataset);
1145: result.setDatasetIndex(datasetIndex);
1146: result.setSeriesKey(dataset.getSeriesKey(series));
1147: result.setSeriesIndex(series);
1148: }
1149: }
1150:
1151: }
1152:
1153: return result;
1154:
1155: }
1156:
1157:
1164: public boolean equals(Object obj) {
1165: if (obj == this) {
1166: return true;
1167: }
1168: if (!(obj instanceof XYDifferenceRenderer)) {
1169: return false;
1170: }
1171: if (!super.equals(obj)) {
1172: return false;
1173: }
1174: XYDifferenceRenderer that = (XYDifferenceRenderer) obj;
1175: if (!PaintUtilities.equal(this.positivePaint, that.positivePaint)) {
1176: return false;
1177: }
1178: if (!PaintUtilities.equal(this.negativePaint, that.negativePaint)) {
1179: return false;
1180: }
1181: if (this.shapesVisible != that.shapesVisible) {
1182: return false;
1183: }
1184: if (!ShapeUtilities.equal(this.legendLine, that.legendLine)) {
1185: return false;
1186: }
1187: if (this.roundXCoordinates != that.roundXCoordinates) {
1188: return false;
1189: }
1190: return true;
1191: }
1192:
1193:
1200: public Object clone() throws CloneNotSupportedException {
1201: XYDifferenceRenderer clone = (XYDifferenceRenderer) super.clone();
1202: clone.legendLine = ShapeUtilities.clone(this.legendLine);
1203: return clone;
1204: }
1205:
1206:
1213: private void writeObject(ObjectOutputStream stream) throws IOException {
1214: stream.defaultWriteObject();
1215: SerialUtilities.writePaint(this.positivePaint, stream);
1216: SerialUtilities.writePaint(this.negativePaint, stream);
1217: SerialUtilities.writeShape(this.legendLine, stream);
1218: }
1219:
1220:
1228: private void readObject(ObjectInputStream stream)
1229: throws IOException, ClassNotFoundException {
1230: stream.defaultReadObject();
1231: this.positivePaint = SerialUtilities.readPaint(stream);
1232: this.negativePaint = SerialUtilities.readPaint(stream);
1233: this.legendLine = SerialUtilities.readShape(stream);
1234: }
1235:
1236: }