001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.data.osm;
003
004 import java.util.ArrayList;
005 import java.util.Arrays;
006 import java.util.List;
007
008 import org.openstreetmap.josm.data.Bounds;
009 import org.openstreetmap.josm.data.coor.LatLon;
010 import org.openstreetmap.josm.tools.Utils;
011
012 public class BBox {
013
014 private double xmin = Double.POSITIVE_INFINITY;
015 private double xmax = Double.NEGATIVE_INFINITY;
016 private double ymin = Double.POSITIVE_INFINITY;
017 private double ymax = Double.NEGATIVE_INFINITY;
018
019 public BBox(Bounds bounds) {
020 add(bounds.getMin());
021 add(bounds.getMax());
022 }
023
024 public BBox(LatLon a, LatLon b) {
025 add(a);
026 add(b);
027 }
028
029 public BBox(BBox copy) {
030 this.xmin = copy.xmin;
031 this.xmax = copy.xmax;
032 this.ymin = copy.ymin;
033 this.ymax = copy.ymax;
034 }
035
036 public BBox(double a_x, double a_y, double b_x, double b_y) {
037 xmin = Math.min(a_x, b_x);
038 xmax = Math.max(a_x, b_x);
039 ymin = Math.min(a_y, b_y);
040 ymax = Math.max(a_y, b_y);
041 sanity();
042 }
043
044 public BBox(Way w) {
045 for (Node n : w.getNodes()) {
046 LatLon coor = n.getCoor();
047 if (coor == null) {
048 continue;
049 }
050 add(coor);
051 }
052 }
053
054 public BBox(Node n) {
055 LatLon coor = n.getCoor();
056 if (coor == null) {
057 xmin = xmax = ymin = ymax = 0;
058 } else {
059 xmin = xmax = coor.lon();
060 ymin = ymax = coor.lat();
061 }
062 }
063
064 private void sanity() {
065 if (xmin < -180.0) {
066 xmin = -180.0;
067 }
068 if (xmax > 180.0) {
069 xmax = 180.0;
070 }
071 if (ymin < -90.0) {
072 ymin = -90.0;
073 }
074 if (ymax > 90.0) {
075 ymax = 90.0;
076 }
077 }
078
079 public void add(LatLon c) {
080 add(c.lon(), c.lat());
081 }
082
083 /**
084 * Extends this bbox to include the point (x, y)
085 */
086 public void add(double x, double y) {
087 xmin = Math.min(xmin, x);
088 xmax = Math.max(xmax, x);
089 ymin = Math.min(ymin, y);
090 ymax = Math.max(ymax, y);
091 sanity();
092 }
093
094 public void add(BBox box) {
095 add(box.getTopLeft());
096 add(box.getBottomRight());
097 }
098
099 public void addPrimitive(OsmPrimitive primitive, double extraSpace) {
100 BBox primBbox = primitive.getBBox();
101 add(primBbox.xmin - extraSpace, primBbox.ymin - extraSpace);
102 add(primBbox.xmax + extraSpace, primBbox.ymax + extraSpace);
103 }
104
105 public double height() {
106 return ymax-ymin;
107 }
108
109 public double width() {
110 return xmax-xmin;
111 }
112
113 /**
114 * Tests, weather the bbox b lies completely inside
115 * this bbox.
116 */
117 public boolean bounds(BBox b) {
118 if (!(xmin <= b.xmin) ||
119 !(xmax >= b.xmax) ||
120 !(ymin <= b.ymin) ||
121 !(ymax >= b.ymax))
122 return false;
123 return true;
124 }
125
126 /**
127 * Tests, weather the Point c lies within the bbox.
128 */
129 public boolean bounds(LatLon c) {
130 if ((xmin <= c.lon()) &&
131 (xmax >= c.lon()) &&
132 (ymin <= c.lat()) &&
133 (ymax >= c.lat()))
134 return true;
135 return false;
136 }
137
138 /**
139 * Tests, weather two BBoxes intersect as an area.
140 * I.e. whether there exists a point that lies in both of them.
141 */
142 public boolean intersects(BBox b) {
143 if (xmin > b.xmax)
144 return false;
145 if (xmax < b.xmin)
146 return false;
147 if (ymin > b.ymax)
148 return false;
149 if (ymax < b.ymin)
150 return false;
151 return true;
152 }
153
154 /**
155 * Returns a list of all 4 corners of the bbox rectangle.
156 */
157 public List<LatLon> points() {
158 LatLon p1 = new LatLon(ymin, xmin);
159 LatLon p2 = new LatLon(ymin, xmax);
160 LatLon p3 = new LatLon(ymax, xmin);
161 LatLon p4 = new LatLon(ymax, xmax);
162 List<LatLon> ret = new ArrayList<LatLon>(4);
163 ret.add(p1);
164 ret.add(p2);
165 ret.add(p3);
166 ret.add(p4);
167 return ret;
168 }
169
170 public LatLon getTopLeft() {
171 return new LatLon(ymax, xmin);
172 }
173
174 public LatLon getBottomRight() {
175 return new LatLon(ymin, xmax);
176 }
177
178 public LatLon getCenter() {
179 return new LatLon(ymin + (ymax-ymin)/2.0, xmin + (xmax-xmin)/2.0);
180 }
181
182 @Override
183 public int hashCode() {
184 return (int)(ymin * xmin);
185 }
186
187 @Override
188 public boolean equals(Object o) {
189 if (o instanceof BBox) {
190 BBox b = (BBox)o;
191 return b.xmax == xmax && b.ymax == ymax && b.xmin == xmin && b.ymin == ymin;
192 } else
193 return false;
194 }
195
196 @Override
197 public String toString() {
198 return "[ x: " + xmin + " -> " + xmax +
199 ", y: " + ymin + " -> " + ymax + " ]";
200 }
201
202 public String toStringCSV(String separator) {
203 return Utils.join(separator, Arrays.asList(
204 LatLon.cDdFormatter.format(xmin),
205 LatLon.cDdFormatter.format(ymin),
206 LatLon.cDdFormatter.format(xmax),
207 LatLon.cDdFormatter.format(ymax)));
208 }
209 }