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