001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * --------------
028 * AxisSpace.java
029 * --------------
030 * (C) Copyright 2003-2008, 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 *
045 */
046
047package org.jfree.chart.axis;
048
049import java.awt.geom.Rectangle2D;
050import java.io.Serializable;
051
052import org.jfree.ui.RectangleEdge;
053import org.jfree.util.PublicCloneable;
054
055/**
056 * A record that contains the space required at each edge of a plot.
057 */
058public class AxisSpace implements Cloneable, PublicCloneable, Serializable {
059
060    /** For serialization. */
061    private static final long serialVersionUID = -2490732595134766305L;
062
063    /** The top space. */
064    private double top;
065
066    /** The bottom space. */
067    private double bottom;
068
069    /** The left space. */
070    private double left;
071
072    /** The right space. */
073    private double right;
074
075    /**
076     * Creates a new axis space record.
077     */
078    public AxisSpace() {
079        this.top = 0.0;
080        this.bottom = 0.0;
081        this.left = 0.0;
082        this.right = 0.0;
083    }
084
085    /**
086     * Returns the space reserved for axes at the top of the plot area.
087     *
088     * @return The space (in Java2D units).
089     */
090    public double getTop() {
091        return this.top;
092    }
093
094    /**
095     * Sets the space reserved for axes at the top of the plot area.
096     *
097     * @param space  the space (in Java2D units).
098     */
099    public void setTop(double space) {
100        this.top = space;
101    }
102
103    /**
104     * Returns the space reserved for axes at the bottom of the plot area.
105     *
106     * @return The space (in Java2D units).
107     */
108    public double getBottom() {
109        return this.bottom;
110    }
111
112    /**
113     * Sets the space reserved for axes at the bottom of the plot area.
114     *
115     * @param space  the space (in Java2D units).
116     */
117    public void setBottom(double space) {
118        this.bottom = space;
119    }
120
121    /**
122     * Returns the space reserved for axes at the left of the plot area.
123     *
124     * @return The space (in Java2D units).
125     */
126    public double getLeft() {
127        return this.left;
128    }
129
130    /**
131     * Sets the space reserved for axes at the left of the plot area.
132     *
133     * @param space  the space (in Java2D units).
134     */
135    public void setLeft(double space) {
136        this.left = space;
137    }
138
139    /**
140     * Returns the space reserved for axes at the right of the plot area.
141     *
142     * @return The space (in Java2D units).
143     */
144    public double getRight() {
145        return this.right;
146    }
147
148    /**
149     * Sets the space reserved for axes at the right of the plot area.
150     *
151     * @param space  the space (in Java2D units).
152     */
153    public void setRight(double space) {
154        this.right = space;
155    }
156
157    /**
158     * Adds space to the top, bottom, left or right edge of the plot area.
159     *
160     * @param space  the space (in Java2D units).
161     * @param edge  the edge (<code>null</code> not permitted).
162     */
163    public void add(double space, RectangleEdge edge) {
164        if (edge == null) {
165            throw new IllegalArgumentException("Null 'edge' argument.");
166        }
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    public Object clone() throws CloneNotSupportedException {
317        return super.clone();
318    }
319
320    /**
321     * Tests this object for equality with another object.
322     *
323     * @param obj  the object to compare against.
324     *
325     * @return <code>true</code> or <code>false</code>.
326     */
327    public boolean equals(Object obj) {
328        if (obj == this) {
329            return true;
330        }
331        if (!(obj instanceof AxisSpace)) {
332            return false;
333        }
334        AxisSpace that = (AxisSpace) obj;
335        if (this.top != that.top) {
336            return false;
337        }
338        if (this.bottom != that.bottom) {
339            return false;
340        }
341        if (this.left != that.left) {
342            return false;
343        }
344        if (this.right != that.right) {
345            return false;
346        }
347        return true;
348    }
349
350    /**
351     * Returns a hash code for this object.
352     *
353     * @return A hash code.
354     */
355    public int hashCode() {
356        int result = 23;
357        long l = Double.doubleToLongBits(this.top);
358        result = 37 * result + (int) (l ^ (l >>> 32));
359        l = Double.doubleToLongBits(this.bottom);
360        result = 37 * result + (int) (l ^ (l >>> 32));
361        l = Double.doubleToLongBits(this.left);
362        result = 37 * result + (int) (l ^ (l >>> 32));
363        l = Double.doubleToLongBits(this.right);
364        result = 37 * result + (int) (l ^ (l >>> 32));
365        return result;
366    }
367
368    /**
369     * Returns a string representing the object (for debugging purposes).
370     *
371     * @return A string.
372     */
373    public String toString() {
374        return super.toString() + "[left=" + this.left + ",right=" + this.right
375                    + ",top=" + this.top + ",bottom=" + this.bottom + "]";
376    }
377
378}