001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data;
003
004import org.openstreetmap.josm.data.coor.EastNorth;
005import org.openstreetmap.josm.tools.Utils;
006
007/**
008 * This is a simple data class for "rectangular" areas of the world, given in
009 * east/north min/max values.
010 *
011 * @author imi
012 */
013public class ProjectionBounds {
014    /**
015     * The minimum east coordinate.
016     */
017    public double minEast;
018    /**
019     * The minimum north coordinate.
020     */
021    public double minNorth;
022    /**
023     * The maximum east coordinate.
024     */
025    public double maxEast;
026    /**
027     * The minimum north coordinate.
028     */
029    public double maxNorth;
030
031    /**
032     * Construct bounds out of two points.
033     * @param min min east/north
034     * @param max max east/north
035     */
036    public ProjectionBounds(EastNorth min, EastNorth max) {
037        this.minEast = min.east();
038        this.minNorth = min.north();
039        this.maxEast = max.east();
040        this.maxNorth = max.north();
041    }
042
043    /**
044     * Construct bounds out of a single point.
045     * @param p east/north
046     */
047    public ProjectionBounds(EastNorth p) {
048        this.minEast = this.maxEast = p.east();
049        this.minNorth = this.maxNorth = p.north();
050    }
051
052    /**
053     * Construct bounds out of a center point and east/north dimensions.
054     * @param center center east/north
055     * @param east east dimension
056     * @param north north dimension
057     */
058    public ProjectionBounds(EastNorth center, double east, double north) {
059        this.minEast = center.east()-east/2.0;
060        this.minNorth = center.north()-north/2.0;
061        this.maxEast = center.east()+east/2.0;
062        this.maxNorth = center.north()+north/2.0;
063    }
064
065    /**
066     * Construct bounds out of two points.
067     * @param minEast min east
068     * @param minNorth min north
069     * @param maxEast max east
070     * @param maxNorth max north
071     */
072    public ProjectionBounds(double minEast, double minNorth, double maxEast, double maxNorth) {
073        this.minEast = minEast;
074        this.minNorth = minNorth;
075        this.maxEast = maxEast;
076        this.maxNorth = maxNorth;
077    }
078
079    /**
080     * Extends bounds to include point {@code e}.
081     * @param e east/north to include
082     */
083    public void extend(EastNorth e) {
084        if (e.east() < minEast) {
085            minEast = e.east();
086        }
087        if (e.east() > maxEast) {
088            maxEast = e.east();
089        }
090        if (e.north() < minNorth) {
091            minNorth = e.north();
092        }
093        if (e.north() > maxNorth) {
094            maxNorth = e.north();
095        }
096    }
097
098    /**
099     * Returns the center east/north.
100     * @return the center east/north
101     */
102    public EastNorth getCenter() {
103        return new EastNorth((minEast + maxEast) / 2.0, (minNorth + maxNorth) / 2.0);
104    }
105
106    @Override
107    public String toString() {
108        return "ProjectionBounds["+minEast+","+minNorth+","+maxEast+","+maxNorth+']';
109    }
110
111    /**
112     * The two bounds intersect? Compared to java Shape.intersects, if does not use
113     * the interior but the closure. ("&gt;=" instead of "&gt;")
114     * @param b projection bounds
115     * @return {@code true} if the two bounds intersect
116     */
117    public boolean intersects(ProjectionBounds b) {
118        return b.maxEast >= minEast &&
119        b.maxNorth >= minNorth &&
120        b.minEast <= maxEast &&
121        b.minNorth <= maxNorth;
122    }
123
124    /**
125     * Check, if a point is within the bounds.
126     * @param en the point
127     * @return true, if <code>en</code> is within the bounds
128     */
129    public boolean contains(EastNorth en) {
130        return minEast <= en.east() && en.east() <= maxEast &&
131                minNorth <= en.north() && en.north() <= maxNorth;
132    }
133
134    /**
135     * Returns the min east/north.
136     * @return the min east/north
137     */
138    public EastNorth getMin() {
139        return new EastNorth(minEast, minNorth);
140    }
141
142    /**
143     * Returns the max east/north.
144     * @return the max east/north
145     */
146    public EastNorth getMax() {
147        return new EastNorth(maxEast, maxNorth);
148    }
149
150    /**
151     * Determines if the bounds area is not null
152     * @return {@code true} if the area is not null
153     */
154    public boolean hasExtend() {
155        return !Utils.equalsEpsilon(minEast, maxEast) || !Utils.equalsEpsilon(minNorth, maxNorth);
156    }
157}