001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 *
027 * --------------
028 * AxisSpace.java
029 * --------------
030 * (C) Copyright 2003-2013, by Object Refinery Limited and Contributors.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes
036 * -------
037 * 03-Jul-2003 : Version 1 (DG);
038 * 14-Aug-2003 : Implemented Cloneable (DG);
039 * 18-Aug-2003 : Implemented Serializable (DG);
040 * 17-Mar-2004 : Added a toString() method for debugging (DG);
041 * 07-Jan-2005 : Updated equals() method (DG);
042 * 11-Jan-2005 : Removed deprecated methods in preparation for 1.0.0
043 *               release (DG);
044 * 02-Jul-2013 : Use ParamChecks (DG);
045 *
046 */
047
048package org.jfree.chart.axis;
049
050import java.awt.geom.Rectangle2D;
051import java.io.Serializable;
052import org.jfree.chart.util.ParamChecks;
053
054import org.jfree.ui.RectangleEdge;
055import org.jfree.util.PublicCloneable;
056
057/**
058 * A record that contains the space required at each edge of a plot.
059 */
060public class AxisSpace implements Cloneable, PublicCloneable, Serializable {
061
062    /** For serialization. */
063    private static final long serialVersionUID = -2490732595134766305L;
064
065    /** The top space. */
066    private double top;
067
068    /** The bottom space. */
069    private double bottom;
070
071    /** The left space. */
072    private double left;
073
074    /** The right space. */
075    private double right;
076
077    /**
078     * Creates a new axis space record.
079     */
080    public AxisSpace() {
081        this.top = 0.0;
082        this.bottom = 0.0;
083        this.left = 0.0;
084        this.right = 0.0;
085    }
086
087    /**
088     * Returns the space reserved for axes at the top of the plot area.
089     *
090     * @return The space (in Java2D units).
091     */
092    public double getTop() {
093        return this.top;
094    }
095
096    /**
097     * Sets the space reserved for axes at the top of the plot area.
098     *
099     * @param space  the space (in Java2D units).
100     */
101    public void setTop(double space) {
102        this.top = space;
103    }
104
105    /**
106     * Returns the space reserved for axes at the bottom of the plot area.
107     *
108     * @return The space (in Java2D units).
109     */
110    public double getBottom() {
111        return this.bottom;
112    }
113
114    /**
115     * Sets the space reserved for axes at the bottom of the plot area.
116     *
117     * @param space  the space (in Java2D units).
118     */
119    public void setBottom(double space) {
120        this.bottom = space;
121    }
122
123    /**
124     * Returns the space reserved for axes at the left of the plot area.
125     *
126     * @return The space (in Java2D units).
127     */
128    public double getLeft() {
129        return this.left;
130    }
131
132    /**
133     * Sets the space reserved for axes at the left of the plot area.
134     *
135     * @param space  the space (in Java2D units).
136     */
137    public void setLeft(double space) {
138        this.left = space;
139    }
140
141    /**
142     * Returns the space reserved for axes at the right of the plot area.
143     *
144     * @return The space (in Java2D units).
145     */
146    public double getRight() {
147        return this.right;
148    }
149
150    /**
151     * Sets the space reserved for axes at the right of the plot area.
152     *
153     * @param space  the space (in Java2D units).
154     */
155    public void setRight(double space) {
156        this.right = space;
157    }
158
159    /**
160     * Adds space to the top, bottom, left or right edge of the plot area.
161     *
162     * @param space  the space (in Java2D units).
163     * @param edge  the edge (<code>null</code> not permitted).
164     */
165    public void add(double space, RectangleEdge edge) {
166        ParamChecks.nullNotPermitted(edge, "edge");
167        if (edge == RectangleEdge.TOP) {
168            this.top += space;
169        }
170        else if (edge == RectangleEdge.BOTTOM) {
171            this.bottom += space;
172        }
173        else if (edge == RectangleEdge.LEFT) {
174            this.left += space;
175        }
176        else if (edge == RectangleEdge.RIGHT) {
177            this.right += space;
178        }
179        else {
180            throw new IllegalStateException("Unrecognised 'edge' argument.");
181        }
182    }
183
184    /**
185     * Ensures that this object reserves at least as much space as another.
186     *
187     * @param space  the other space.
188     */
189    public void ensureAtLeast(AxisSpace space) {
190        this.top = Math.max(this.top, space.top);
191        this.bottom = Math.max(this.bottom, space.bottom);
192        this.left = Math.max(this.left, space.left);
193        this.right = Math.max(this.right, space.right);
194    }
195
196    /**
197     * Ensures there is a minimum amount of space at the edge corresponding to
198     * the specified axis location.
199     *
200     * @param space  the space.
201     * @param edge  the location.
202     */
203    public void ensureAtLeast(double space, RectangleEdge edge) {
204        if (edge == RectangleEdge.TOP) {
205            if (this.top < space) {
206                this.top = space;
207            }
208        }
209        else if (edge == RectangleEdge.BOTTOM) {
210            if (this.bottom < space) {
211                this.bottom = space;
212            }
213        }
214        else if (edge == RectangleEdge.LEFT) {
215            if (this.left < space) {
216                this.left = space;
217            }
218        }
219        else if (edge == RectangleEdge.RIGHT) {
220            if (this.right < space) {
221                this.right = space;
222            }
223        }
224        else {
225            throw new IllegalStateException(
226                "AxisSpace.ensureAtLeast(): unrecognised AxisLocation."
227            );
228        }
229    }
230
231    /**
232     * Shrinks an area by the space attributes.
233     *
234     * @param area  the area to shrink.
235     * @param result  an optional carrier for the result.
236     *
237     * @return The result.
238     */
239    public Rectangle2D shrink(Rectangle2D area, Rectangle2D result) {
240        if (result == null) {
241            result = new Rectangle2D.Double();
242        }
243        result.setRect(
244            area.getX() + this.left,
245            area.getY() + this.top,
246            area.getWidth() - this.left - this.right,
247            area.getHeight() - this.top - this.bottom
248        );
249        return result;
250    }
251
252    /**
253     * Expands an area by the amount of space represented by this object.
254     *
255     * @param area  the area to expand.
256     * @param result  an optional carrier for the result.
257     *
258     * @return The result.
259     */
260    public Rectangle2D expand(Rectangle2D area, Rectangle2D result) {
261        if (result == null) {
262            result = new Rectangle2D.Double();
263        }
264        result.setRect(
265            area.getX() - this.left,
266            area.getY() - this.top,
267            area.getWidth() + this.left + this.right,
268            area.getHeight() + this.top + this.bottom
269        );
270        return result;
271    }
272
273    /**
274     * Calculates the reserved area.
275     *
276     * @param area  the area.
277     * @param edge  the edge.
278     *
279     * @return The reserved area.
280     */
281    public Rectangle2D reserved(Rectangle2D area, RectangleEdge edge) {
282        Rectangle2D result = null;
283        if (edge == RectangleEdge.TOP) {
284            result = new Rectangle2D.Double(
285                area.getX(), area.getY(), area.getWidth(), this.top
286            );
287        }
288        else if (edge == RectangleEdge.BOTTOM) {
289            result = new Rectangle2D.Double(
290                area.getX(), area.getMaxY() - this.top,
291                area.getWidth(), this.bottom
292            );
293        }
294        else if (edge == RectangleEdge.LEFT) {
295            result = new Rectangle2D.Double(
296                area.getX(), area.getY(), this.left, area.getHeight()
297            );
298        }
299        else if (edge == RectangleEdge.RIGHT) {
300            result = new Rectangle2D.Double(
301                area.getMaxX() - this.right, area.getY(),
302                this.right, area.getHeight()
303            );
304        }
305        return result;
306    }
307
308    /**
309     * Returns a clone of the object.
310     *
311     * @return A clone.
312     *
313     * @throws CloneNotSupportedException This class won't throw this exception,
314     *         but subclasses (if any) might.
315     */
316    @Override
317    public Object clone() throws CloneNotSupportedException {
318        return super.clone();
319    }
320
321    /**
322     * Tests this object for equality with another object.
323     *
324     * @param obj  the object to compare against.
325     *
326     * @return <code>true</code> or <code>false</code>.
327     */
328    @Override
329    public boolean equals(Object obj) {
330        if (obj == this) {
331            return true;
332        }
333        if (!(obj instanceof AxisSpace)) {
334            return false;
335        }
336        AxisSpace that = (AxisSpace) obj;
337        if (this.top != that.top) {
338            return false;
339        }
340        if (this.bottom != that.bottom) {
341            return false;
342        }
343        if (this.left != that.left) {
344            return false;
345        }
346        if (this.right != that.right) {
347            return false;
348        }
349        return true;
350    }
351
352    /**
353     * Returns a hash code for this object.
354     *
355     * @return A hash code.
356     */
357    @Override
358    public int hashCode() {
359        int result = 23;
360        long l = Double.doubleToLongBits(this.top);
361        result = 37 * result + (int) (l ^ (l >>> 32));
362        l = Double.doubleToLongBits(this.bottom);
363        result = 37 * result + (int) (l ^ (l >>> 32));
364        l = Double.doubleToLongBits(this.left);
365        result = 37 * result + (int) (l ^ (l >>> 32));
366        l = Double.doubleToLongBits(this.right);
367        result = 37 * result + (int) (l ^ (l >>> 32));
368        return result;
369    }
370
371    /**
372     * Returns a string representing the object (for debugging purposes).
373     *
374     * @return A string.
375     */
376    @Override
377    public String toString() {
378        return super.toString() + "[left=" + this.left + ",right=" + this.right
379                    + ",top=" + this.top + ",bottom=" + this.bottom + "]";
380    }
381
382}