sascha@422: package de.intevation.gnv.jfreechart;
sascha@422: 
sascha@422: import java.awt.AlphaComposite;
sascha@422: import java.awt.Composite;
sascha@422: import java.awt.Graphics2D;
sascha@422: import java.awt.Shape;
sascha@422: 
sascha@422: import java.awt.geom.Point2D;
sascha@422: import java.awt.geom.Rectangle2D;
sascha@422: 
sascha@422: import java.util.HashMap;
sascha@422: import java.util.Iterator;
sascha@422: import java.util.Map;
sascha@422: 
sascha@422: import org.jfree.chart.axis.Axis;
sascha@422: import org.jfree.chart.axis.AxisCollection;
sascha@422: import org.jfree.chart.axis.AxisLocation;
sascha@422: import org.jfree.chart.axis.AxisSpace;
sascha@422: import org.jfree.chart.axis.AxisState;
sascha@422: import org.jfree.chart.axis.ValueAxis;
sascha@422: 
sascha@422: import org.jfree.chart.plot.Plot;
sascha@779: import org.jfree.chart.plot.PlotOrientation;
sascha@422: import org.jfree.chart.plot.PlotRenderingInfo;
sascha@422: import org.jfree.chart.plot.PlotState;
sascha@422: 
sascha@422: import org.jfree.data.Range;
sascha@422: 
sascha@422: import org.jfree.ui.RectangleEdge;
sascha@422: import org.jfree.ui.RectangleInsets;
sascha@422: 
sascha@422: import org.jfree.util.ObjectList;
sascha@422: 
sascha@422: /**
ingo@795:  * A class for plotting polygons into a 2D chart. This plot makes use of <code>
ingo@795:  * PolygonRenderer</code>.
sascha@803:  *
sascha@780:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
sascha@422:  */
sascha@422: // TODO implement cloneable
sascha@422: public class PolygonPlot
sascha@422: extends      Plot
sascha@422: {
sascha@422:     public static final String PLOT_TYPE = "PolygonPlot";
sascha@422: 
sascha@422:     public static final PlotOrientation DEFAULT_PLOT_ORIENTATION =
sascha@422:         PlotOrientation.VERTICAL;
sascha@422: 
sascha@422:     private PolygonDataset  dataset;
sascha@422:     private transient PolygonRenderer renderer;
sascha@422: 
sascha@422:     private PlotOrientation orientation;
sascha@422: 
sascha@422:     private RectangleInsets axisOffset;
sascha@422: 
sascha@422:     private ObjectList      domainAxisLocation;
sascha@422:     private ObjectList      rangeAxisLocation;
sascha@422:     private ObjectList      domainAxes;
sascha@422:     private ObjectList      rangeAxes;
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * Constructs a new PolygonPlot with a dataset and a renderer.
ingo@795:      *
ingo@795:      * @param dataset Dataset containing polygons.
ingo@795:      * @param renderer The renderer used to draw polygons.
ingo@795:      */
sascha@422:     public PolygonPlot(PolygonDataset dataset, PolygonRenderer renderer) {
sascha@422:         this(dataset, renderer, null, null, PlotOrientation.HORIZONTAL);
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * @param dataset Dataset containing polygons.
ingo@795:      * @param renderer The renderer used to draw polygons.
ingo@795:      * @param orientation The orientation used for this plot.
ingo@795:      */
sascha@422:     public PolygonPlot(
sascha@422:         PolygonDataset  dataset,
sascha@422:         PolygonRenderer renderer,
sascha@422:         PlotOrientation orientation
sascha@422:     ) {
sascha@422:         this(dataset, renderer, null, null, orientation);
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * @param dataset Dataset containing polygons.
ingo@795:      * @param renderer The renderer used to draw polygons.
ingo@795:      * @param domainAxis The x axis.
ingo@795:      * @param rangeAxis The y axis.
ingo@795:      * @param orientation The orientation used for this plot.
ingo@795:      */
sascha@422:     public PolygonPlot(
sascha@422:         PolygonDataset  dataset,
sascha@422:         PolygonRenderer renderer,
sascha@422:         ValueAxis       domainAxis,
sascha@422:         ValueAxis       rangeAxis,
sascha@422:         PlotOrientation orientation
sascha@422:     ) {
sascha@422:         super();
sascha@422: 
sascha@422:         this.dataset            = dataset;
sascha@422:         this.renderer           = renderer;
sascha@422:         this.domainAxes         = new ObjectList();
sascha@422:         this.rangeAxes          = new ObjectList();
sascha@422:         this.domainAxisLocation = new ObjectList();
sascha@422:         this.rangeAxisLocation  = new ObjectList();
sascha@422:         this.axisOffset         = RectangleInsets.ZERO_INSETS;
sascha@422: 
sascha@422:         if (orientation != null)
sascha@422:             this.orientation = orientation;
sascha@422:         else
sascha@422:             this.orientation = DEFAULT_PLOT_ORIENTATION;
sascha@422: 
sascha@422:         if (domainAxis != null) {
sascha@422:             this.domainAxes.set(0, domainAxis);
sascha@422:             domainAxis.setPlot(this);
sascha@422:         }
sascha@422:         domainAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
sascha@422: 
sascha@422:         if (rangeAxis != null) {
sascha@422:             this.rangeAxes.set(0, rangeAxis);
sascha@422:             rangeAxis.setPlot(this);
sascha@422:         }
sascha@422:         rangeAxisLocation.set(0, AxisLocation.BOTTOM_OR_LEFT);
sascha@422: 
sascha@422:         configureDomainAxis();
sascha@422:         configureRangeAxis();
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     public void configureDomainAxis() {
sascha@422:         // we just have 1 dataset
sascha@422:         Range domainAxisRange = getDataset().getDomainBounds();
sascha@422: 
sascha@422:         for (int i = 0; i < domainAxes.size(); i++) {
sascha@422:             ValueAxis axis = (ValueAxis) domainAxes.get(i);
sascha@422: 
sascha@422:             if (axis != null) {
sascha@422:                 axis.configure();
sascha@422:                 axis.setRange(domainAxisRange);
sascha@422:             }
sascha@422:         }
sascha@422:     }
sascha@422: 
sascha@450:     public ValueAxis getDomainAxis() {
sascha@450:         return getDomainAxis(0);
sascha@450:     }
sascha@450: 
ingo@841:     public void setDomainAxis(ValueAxis axis) {
ingo@841:         domainAxes.set(0, axis);
ingo@841:     }
ingo@841: 
sascha@450:     public ValueAxis getDomainAxis(int index) {
sascha@450:         return index < domainAxes.size()
sascha@450:             ? (ValueAxis)domainAxes.get(index)
sascha@450:             : null;
sascha@450:     }
sascha@450: 
sascha@450:     public ValueAxis getRangeAxis() {
sascha@450:         return getRangeAxis(0);
sascha@450:     }
sascha@450: 
ingo@841:     public void setRangeAxis(ValueAxis axis) {
ingo@841:         rangeAxes.set(0, axis);
ingo@841:     }
ingo@841: 
sascha@450:     public ValueAxis getRangeAxis(int index) {
sascha@450:         return index < rangeAxes.size()
sascha@450:             ? (ValueAxis)rangeAxes.get(index)
sascha@450:             : null;
sascha@450:     }
sascha@422: 
sascha@422:     public  void configureRangeAxis() {
sascha@422:         // we just have 1 dataset
sascha@422:         Range rangeAxisRange = getDataset().getRangeBounds();
sascha@422: 
sascha@422:         for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422:             ValueAxis axis = (ValueAxis) rangeAxes.get(i);
sascha@422: 
sascha@422:             if (axis != null) {
sascha@422:                 axis.configure();
sascha@422:                 axis.setRange(rangeAxisRange);
sascha@422:             }
sascha@422:         }
sascha@422:     }
sascha@422: 
sascha@422:     public PolygonDataset getDataset(){
sascha@422:         return this.dataset;
sascha@422:     }
sascha@422: 
sascha@422:     public String getPlotType() {
sascha@422:         return PLOT_TYPE;
sascha@422:     }
sascha@422: 
sascha@422:     public  void setDataset(PolygonDataset dataset) {
sascha@422:         this.dataset = dataset;
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * This is the major method to draw the into a given Graphic2D object.
ingo@795:      *
ingo@795:      * @param g2 Graphics object where the plot is drawn into.
ingo@795:      * @param area The bounds for drawing this plot.
ingo@795:      * @param anchor An anchor point.
ingo@795:      * @param parentState The plot state.
ingo@795:      * @param info
ingo@795:      */
sascha@422:     public void draw(
sascha@422:         Graphics2D        g2,
sascha@422:         Rectangle2D       area,
sascha@422:         Point2D           anchor,
sascha@422:         PlotState         parentState,
sascha@422:         PlotRenderingInfo info
sascha@422:     ) {
sascha@422:         Graphics2D  savedG2       = g2;
sascha@422:         Rectangle2D savedDataArea = area;
sascha@422: 
sascha@422:         if (info != null) {
sascha@422:             info.setPlotArea(area);
sascha@422:             info.setDataArea(area);
sascha@422:         }
sascha@422: 
sascha@422:         AxisSpace space      = calculateAxisSpace(g2, area);
sascha@422:         Rectangle2D dataArea = space.shrink(area, null);
sascha@422: 
sascha@422:         // draw background and outline
sascha@422:         drawBackground(g2, area);
sascha@422:         drawOutline(g2, area);
sascha@422: 
sascha@422:         Shape savedClip = g2.getClip();
sascha@422:         g2.clip(area);
sascha@422: 
sascha@422:         Composite originalComposite = g2.getComposite();
sascha@422:         g2.setComposite(AlphaComposite.getInstance(
sascha@422:             AlphaComposite.SRC_OVER,
sascha@422:             getForegroundAlpha()
sascha@422:         ));
sascha@778: 
sascha@422:         // draw axis
sascha@422:         drawAxes(g2, area, dataArea, info);
sascha@422: 
sascha@422:         if (!isEmptyOrNull(dataset)) {
sascha@422:             // draw data
sascha@422:             drawPolygons(savedG2, dataArea, info);
sascha@450:             drawLabels(savedG2, dataArea, info);
sascha@422:         }
sascha@422: 
sascha@422:         g2.setClip(savedClip);
sascha@422:         g2.setComposite(originalComposite);
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * Method to draw the axis for this plot.
sascha@803:      *
ingo@795:      * @param g2
ingo@795:      * @param plotArea
ingo@795:      * @param dataArea
ingo@795:      * @param plotState
ingo@795:      */
sascha@422:     private void drawAxes(
sascha@422:         Graphics2D        g2,
sascha@422:         Rectangle2D       plotArea,
sascha@422:         Rectangle2D       dataArea,
sascha@422:         PlotRenderingInfo plotState
sascha@422:     ) {
sascha@422:         AxisCollection axisCollection = new AxisCollection();
sascha@422: 
sascha@422:         for (int i = 0; i < domainAxes.size(); i++) {
sascha@422:             ValueAxis axis = (ValueAxis) domainAxes.get(i);
sascha@422:             if (axis != null)
sascha@422:                 axisCollection.add(axis, getDomainAxisEdge(i));
sascha@422:         }
sascha@422: 
sascha@422:         for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422:             ValueAxis axis = (ValueAxis) rangeAxes.get(i);
sascha@422:             if (axis != null)
sascha@422:                 axisCollection.add(axis, getRangeAxisEdge(i));
sascha@422:         }
sascha@422: 
sascha@422:         Map axisStateMap = new HashMap();
sascha@422: 
sascha@422:         // draw the top axes
sascha@422:         double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(
sascha@422:                 dataArea.getHeight());
sascha@422:         Iterator iterator = axisCollection.getAxesAtTop().iterator();
sascha@422:         while (iterator.hasNext()) {
sascha@422:             ValueAxis axis = (ValueAxis) iterator.next();
sascha@422:             AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422:                     RectangleEdge.TOP, plotState);
sascha@422:             cursor = info.getCursor();
sascha@422:             axisStateMap.put(axis, info);
sascha@422:         }
sascha@422: 
sascha@422:         // draw the bottom axes
sascha@422:         cursor = dataArea.getMaxY()
sascha@422:                  + this.axisOffset.calculateBottomOutset(dataArea.getHeight());
sascha@422:         iterator = axisCollection.getAxesAtBottom().iterator();
sascha@422:         while (iterator.hasNext()) {
sascha@422:             ValueAxis axis = (ValueAxis) iterator.next();
sascha@422:             AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422:                     RectangleEdge.BOTTOM, plotState);
sascha@422:             cursor = info.getCursor();
sascha@422:             axisStateMap.put(axis, info);
sascha@422:         }
sascha@422: 
sascha@422:         // draw the left axes
sascha@422:         cursor = dataArea.getMinX()
sascha@422:                  - this.axisOffset.calculateLeftOutset(dataArea.getWidth());
sascha@422:         iterator = axisCollection.getAxesAtLeft().iterator();
sascha@422:         while (iterator.hasNext()) {
sascha@422:             ValueAxis axis = (ValueAxis) iterator.next();
sascha@422:             AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422:                     RectangleEdge.LEFT, plotState);
sascha@422:             cursor = info.getCursor();
sascha@422:             axisStateMap.put(axis, info);
sascha@422:         }
sascha@422: 
sascha@422:         // draw the right axes
sascha@422:         cursor = dataArea.getMaxX()
sascha@422:                  + this.axisOffset.calculateRightOutset(dataArea.getWidth());
sascha@422:         iterator = axisCollection.getAxesAtRight().iterator();
sascha@422:         while (iterator.hasNext()) {
sascha@422:             ValueAxis axis = (ValueAxis) iterator.next();
sascha@422:             AxisState info = axis.draw(g2, cursor, plotArea, dataArea,
sascha@422:                     RectangleEdge.RIGHT, plotState);
sascha@422:             cursor = info.getCursor();
sascha@422:             axisStateMap.put(axis, info);
sascha@422:         }
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * Put some labels at data items into the plot. Uses PolygonRenderer to do
ingo@795:      * this job.
ingo@795:      *
ingo@795:      * @param g2
ingo@795:      * @param area
ingo@795:      * @param info
ingo@795:      */
sascha@450:     private void drawLabels(
sascha@450:         Graphics2D        g2,
sascha@450:         Rectangle2D       area,
sascha@450:         PlotRenderingInfo info
sascha@450:     ) {
sascha@450:         renderer.drawLabels(g2, this, area, dataset);
sascha@450:     }
sascha@450: 
ingo@795: 
ingo@795:     /**
ingo@795:      * Plot the polygons. Uses PolygonRenderer to do this job.
sascha@803:      *
ingo@795:      * @param g2
ingo@795:      * @param area
ingo@795:      * @param info
ingo@795:      */
sascha@422:     private void drawPolygons(
sascha@422:         Graphics2D        g2,
sascha@422:         Rectangle2D       area,
sascha@422:         PlotRenderingInfo info
sascha@422:     ) {
sascha@451:         renderer.drawPolygons(g2, this, area, dataset);
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     private AxisSpace calculateAxisSpace(Graphics2D  g2, Rectangle2D plotArea) {
sascha@422:         AxisSpace space         = new AxisSpace();
sascha@422:         space                   = calculateRangeAxisSpace(g2, plotArea, space);
sascha@422:         Rectangle2D tmpPlotArea = space.shrink(plotArea, null);
sascha@422:         space                   = calculateDomainAxisSpace(g2, plotArea, space);
sascha@422: 
sascha@422:         return space;
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     private AxisSpace calculateDomainAxisSpace(
sascha@422:         Graphics2D  g2,
sascha@422:         Rectangle2D plotArea,
sascha@422:         AxisSpace   space
sascha@422:     ) {
sascha@422:         if (space == null)
sascha@422:             space = new AxisSpace();
sascha@422: 
sascha@422:         for (int i = 0; i < domainAxes.size(); i++) {
sascha@422:             Axis axis = (Axis) domainAxes.get(i);
sascha@422: 
sascha@422:             if (axis != null) {
sascha@422:                 RectangleEdge edge = getDomainAxisEdge(i);
sascha@422:                 space = axis.reserveSpace(g2, this, plotArea, edge, space);
sascha@422:             }
sascha@422:         }
sascha@422: 
sascha@422:         return space;
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     private AxisSpace calculateRangeAxisSpace(
sascha@422:         Graphics2D  g2,
sascha@422:         Rectangle2D plotArea,
sascha@422:         AxisSpace   space
sascha@422:     ) {
sascha@422:         if (space == null)
sascha@422:             space = new AxisSpace();
sascha@422: 
sascha@422:         for (int i = 0; i < rangeAxes.size(); i++) {
sascha@422:             Axis axis = (Axis) rangeAxes.get(i);
sascha@422: 
sascha@422:             if (axis != null) {
sascha@422:                 RectangleEdge edge = getRangeAxisEdge(i);
sascha@422:                 space = axis.reserveSpace(g2, this, plotArea, edge, space);
sascha@422:             }
sascha@422:         }
sascha@422: 
sascha@422:         return space;
sascha@422:     }
sascha@422: 
ingo@795: 
sascha@450:     public RectangleEdge getDomainAxisEdge() {
sascha@422:         return Plot.resolveDomainAxisLocation(
sascha@422:             getDomainAxisLocation(), orientation
sascha@422:         );
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@450:     public RectangleEdge getDomainAxisEdge(int idx) {
sascha@422:         AxisLocation  location = getDomainAxisLocation(idx);
sascha@422:         RectangleEdge result   = Plot.resolveDomainAxisLocation(
sascha@422:             location, orientation
sascha@422:         );
sascha@422: 
sascha@422:         if (result == null)
sascha@422:             result = RectangleEdge.opposite(getDomainAxisEdge());
sascha@422: 
sascha@422:         return result;
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@450:     public RectangleEdge getRangeAxisEdge() {
sascha@422:         return Plot.resolveRangeAxisLocation(
sascha@422:             getRangeAxisLocation(), orientation
sascha@422:         );
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@450:     public RectangleEdge getRangeAxisEdge(int idx) {
sascha@422:         AxisLocation  location = getRangeAxisLocation(idx);
sascha@422:         RectangleEdge result   = Plot.resolveRangeAxisLocation(
sascha@422:             location,
sascha@422:             orientation
sascha@422:         );
sascha@422: 
sascha@422:         if (result == null)
sascha@422:             result = RectangleEdge.opposite(getRangeAxisEdge());
sascha@422: 
sascha@422:         return result;
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     public AxisLocation getDomainAxisLocation() {
sascha@422:         return (AxisLocation) domainAxisLocation.get(0);
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     public AxisLocation getDomainAxisLocation(int idx) {
sascha@422:         if (idx < domainAxisLocation.size())
sascha@422:             return (AxisLocation) domainAxisLocation.get(idx);
sascha@422: 
sascha@422:         return null;
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     public AxisLocation getRangeAxisLocation() {
sascha@422:         return (AxisLocation) rangeAxisLocation.get(0);
sascha@422:     }
sascha@422: 
sascha@422: 
sascha@422:     public AxisLocation getRangeAxisLocation(int idx) {
sascha@422:         if (idx < rangeAxisLocation.size())
sascha@422:             return (AxisLocation) rangeAxisLocation.get(idx);
sascha@422: 
sascha@422:         return null;
sascha@422:     }
sascha@422: 
sascha@422: 
ingo@795:     /**
ingo@795:      * @return true, if dataset is null or if it does not contain any
ingo@795:      * PolygonSeries, otherwise false.
ingo@795:      */
sascha@422:     private boolean isEmptyOrNull(PolygonDataset dataset) {
sascha@422:         if (dataset != null) {
sascha@422:             int seriesCount = dataset.getSeriesCount();
sascha@422:             for (int s = 0; s < seriesCount; s++) {
sascha@422:                 PolygonSeries series = dataset.getSeries(s);
sascha@422:                 if (series.getItemCount() > 0) {
sascha@422:                     return false;
sascha@422:                 }
sascha@422:             }
sascha@422:         }
sascha@422:         return true;
sascha@422:     }
sascha@422: }
sascha@836: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :