Index: trunk/src/org/openstreetmap/josm/data/Bounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 17702)
+++ trunk/src/org/openstreetmap/josm/data/Bounds.java	(revision 17703)
@@ -22,5 +22,5 @@
  * @see BBox to represent invalid areas.
  */
-public class Bounds {
+public class Bounds implements IBounds {
     /**
      * The minimum and maximum coordinates.
@@ -32,4 +32,5 @@
      * @return The point
      */
+    @Override
     public LatLon getMin() {
         return new LatLon(minLat, minLon);
@@ -42,4 +43,5 @@
      * @since 6203
      */
+    @Override
     public double getMinLat() {
         return minLat;
@@ -52,4 +54,5 @@
      * @since 6203
      */
+    @Override
     public double getMinLon() {
         return minLon;
@@ -60,4 +63,5 @@
      * @return The point
      */
+    @Override
     public LatLon getMax() {
         return new LatLon(maxLat, maxLon);
@@ -70,4 +74,5 @@
      * @since 6203
      */
+    @Override
     public double getMaxLat() {
         return maxLat;
@@ -80,4 +85,5 @@
      * @since 6203
      */
+    @Override
     public double getMaxLon() {
         return maxLon;
@@ -364,4 +370,5 @@
      * @return Center of the bounding box.
      */
+    @Override
     public LatLon getCenter() {
         if (crosses180thMeridian()) {
@@ -446,4 +453,5 @@
      * @since 12161
      */
+    @Override
     public boolean contains(ILatLon ll) {
         if (!ll.isLatLonKnown()) {
@@ -462,6 +470,6 @@
     }
 
-    private static boolean intersectsLonCrossing(Bounds crossing, Bounds notCrossing) {
-        return notCrossing.minLon <= crossing.maxLon || notCrossing.maxLon >= crossing.minLon;
+    private static boolean intersectsLonCrossing(IBounds crossing, IBounds notCrossing) {
+        return notCrossing.getMinLon() <= crossing.getMaxLon() || notCrossing.getMaxLon() >= crossing.getMinLon();
     }
 
@@ -473,5 +481,10 @@
      */
     public boolean intersects(Bounds b) {
-        if (b.maxLat < minLat || b.minLat > maxLat)
+        return intersects((IBounds) b);
+    }
+
+    @Override
+    public boolean intersects(IBounds b) {
+        if (b.getMaxLat() < minLat || b.getMinLat() > maxLat)
             return false;
 
@@ -483,5 +496,5 @@
             return true;
         } else {
-            return b.maxLon >= minLon && b.minLon <= maxLon;
+            return b.getMaxLon() >= minLon && b.getMinLon() <= maxLon;
         }
     }
@@ -492,4 +505,5 @@
      * @return true if this Bounds object crosses the 180th Meridian.
      */
+    @Override
     public boolean crosses180thMeridian() {
         return this.minLon > this.maxLon;
@@ -509,4 +523,5 @@
      * @since 14521
      */
+    @Override
     public double getHeight() {
         return maxLat-minLat;
@@ -518,4 +533,5 @@
      * @since 14521
      */
+    @Override
     public double getWidth() {
         return maxLon-minLon + (crosses180thMeridian() ? 360.0 : 0.0);
@@ -526,4 +542,5 @@
      * @return The area
      */
+    @Override
     public double getArea() {
         return getWidth() * getHeight();
Index: trunk/src/org/openstreetmap/josm/data/IBounds.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/IBounds.java	(revision 17703)
+++ trunk/src/org/openstreetmap/josm/data/IBounds.java	(revision 17703)
@@ -0,0 +1,146 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data;
+
+import org.openstreetmap.josm.data.coor.ILatLon;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.BBox;
+
+/**
+ * Represents a "rectangular" area of the world, given in lat/lon min/max values.
+ *
+ * @since 17703
+ */
+public interface IBounds {
+
+    /**
+     * Gets the point that has both the minimal lat and lon coordinate
+     *
+     * @return The point
+     */
+    default ILatLon getMin() {
+        return new LatLon(getMinLat(), getMinLon());
+    }
+
+    /**
+     * Returns min latitude of bounds. Efficient shortcut for {@code getMin().lat()}.
+     *
+     * @return min latitude of bounds.
+     */
+    double getMinLat();
+
+    /**
+     * Returns min longitude of bounds. Efficient shortcut for {@code getMin().lon()}.
+     *
+     * @return min longitude of bounds.
+     */
+    double getMinLon();
+
+    /**
+     * Gets the point that has both the maximum lat and lon coordinate
+     *
+     * @return The point
+     */
+    default ILatLon getMax() {
+        return new LatLon(getMaxLat(), getMaxLon());
+    }
+
+    /**
+     * Returns max latitude of bounds. Efficient shortcut for {@code getMax().lat()}.
+     *
+     * @return max latitude of bounds.
+     */
+    double getMaxLat();
+
+    /**
+     * Returns max longitude of bounds. Efficient shortcut for {@code getMax().lon()}.
+     *
+     * @return max longitude of bounds.
+     */
+    double getMaxLon();
+
+    /**
+     * Returns center of the bounding box.
+     *
+     * @return Center of the bounding box.
+     */
+    ILatLon getCenter();
+
+    /**
+     * Determines if the given point {@code ll} is within these bounds.
+     * <p>
+     * Points with unknown coordinates are always outside the coordinates.
+     *
+     * @param ll The lat/lon to check
+     * @return {@code true} if {@code ll} is within these bounds, {@code false} otherwise
+     */
+    default boolean contains(ILatLon ll) {
+        return getMinLon() <= ll.lon() && ll.lon() <= getMaxLon()
+                && getMinLat() <= ll.lat() && ll.lat() <= getMaxLat();
+    }
+
+    /**
+     * Tests, whether the bbox {@code b} lies completely inside this bbox.
+     *
+     * @param b bounding box
+     * @return {@code true} if {@code b} lies completely inside this bbox
+     */
+    default boolean contains(IBounds b) {
+        return getMinLon() <= b.getMinLon() && getMaxLon() >= b.getMaxLon()
+                && getMinLat() <= b.getMinLat() && getMaxLat() >= b.getMaxLat();
+    }
+
+    /**
+     * The two bounds intersect? Compared to java Shape.intersects, if does not use
+     * the interior but the closure. ("&gt;=" instead of "&gt;")
+     *
+     * @param b other bounds
+     * @return {@code true} if the two bounds intersect
+     */
+    default boolean intersects(IBounds b) {
+        return getMinLon() <= b.getMaxLon() && getMaxLon() >= b.getMinLon()
+                && getMinLat() <= b.getMaxLat() && getMaxLat() >= b.getMinLat();
+    }
+
+    /**
+     * Returns the bounds width.
+     *
+     * @return the bounds width
+     */
+    double getHeight();
+
+    /**
+     * Returns the bounds width.
+     *
+     * @return the bounds width
+     */
+    double getWidth();
+
+    /**
+     * Gets the area of this bounds (in lat/lon space)
+     *
+     * @return The area
+     */
+    default double getArea() {
+        return getWidth() * getHeight();
+    }
+
+    /**
+     * Determines if the bbox covers a part of the planet surface.
+     *
+     * @return true if the bbox covers a part of the planet surface.
+     * Height and width must be non-negative, but may (both) be 0.
+     */
+    default boolean isValid() {
+        return true;
+    }
+
+    /**
+     * Determines if this Bounds object crosses the 180th Meridian.
+     * See http://wiki.openstreetmap.org/wiki/180th_meridian
+     *
+     * @return true if this Bounds object crosses the 180th Meridian.
+     */
+    default boolean crosses180thMeridian() {
+        return false;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/BBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/BBox.java	(revision 17702)
+++ trunk/src/org/openstreetmap/josm/data/osm/BBox.java	(revision 17703)
@@ -6,4 +6,5 @@
 
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.IBounds;
 import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -15,5 +16,5 @@
  * In contrast to a {@link Bounds} object, a BBox can represent an invalid (empty) area.
  */
-public class BBox {
+public class BBox implements IBounds {
 
     protected double xmin = Double.POSITIVE_INFINITY;
@@ -173,7 +174,7 @@
      */
     public void addPrimitive(OsmPrimitive primitive, double extraSpace) {
-        BBox primBbox = primitive.getBBox();
-        add(primBbox.xmin - extraSpace, primBbox.ymin - extraSpace);
-        add(primBbox.xmax + extraSpace, primBbox.ymax + extraSpace);
+        IBounds primBbox = primitive.getBBox();
+        add(primBbox.getMinLon() - extraSpace, primBbox.getMinLat() - extraSpace);
+        add(primBbox.getMaxLon() + extraSpace, primBbox.getMaxLat() + extraSpace);
     }
 
@@ -196,4 +197,9 @@
      */
     public double height() {
+        return getHeight();
+    }
+
+    @Override
+    public double getHeight() {
         if (isValid()) {
             return ymax - ymin;
@@ -208,4 +214,9 @@
      */
     public double width() {
+        return getWidth();
+    }
+
+    @Override
+    public double getWidth() {
         if (isValid()) {
             return xmax - xmin;
@@ -229,6 +240,5 @@
      */
     public boolean bounds(BBox b) {
-        return xmin <= b.xmin && xmax >= b.xmax
-            && ymin <= b.ymin && ymax >= b.ymax;
+        return contains(b);
     }
 
@@ -239,6 +249,5 @@
      */
     public boolean bounds(LatLon c) {
-        return xmin <= c.lon() && xmax >= c.lon()
-            && ymin <= c.lat() && ymax >= c.lat();
+        return contains(c);
     }
 
@@ -250,6 +259,5 @@
      */
     public boolean intersects(BBox b) {
-        return xmin <= b.xmax && xmax >= b.xmin
-            && ymin <= b.ymax && ymax >= b.ymin;
+        return intersects((IBounds) b);
     }
 
@@ -268,4 +276,9 @@
      */
     public double getTopLeftLat() {
+        return getMaxLat();
+    }
+
+    @Override
+    public double getMaxLat() {
         return ymax;
     }
@@ -277,4 +290,9 @@
      */
     public double getTopLeftLon() {
+        return getMinLon();
+    }
+
+    @Override
+    public double getMinLon() {
         return xmin;
     }
@@ -294,4 +312,9 @@
      */
     public double getBottomRightLat() {
+        return getMinLat();
+    }
+
+    @Override
+    public double getMinLat() {
         return ymin;
     }
@@ -303,4 +326,9 @@
      */
     public double getBottomRightLon() {
+        return getMaxLon();
+    }
+
+    @Override
+    public double getMaxLon() {
         return xmax;
     }
@@ -310,4 +338,5 @@
      * @return The center.
      */
+    @Override
     public LatLon getCenter() {
         return new LatLon(ymin + (ymax-ymin)/2.0, xmin + (xmax-xmin)/2.0);
@@ -391,4 +420,5 @@
      * @since 11269
      */
+    @Override
     public boolean isValid() {
         return xmin <= xmax && ymin <= ymax;
