Index: src/org/openstreetmap/josm/data/osm/BBox.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/BBox.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/BBox.java	(working copy)
@@ -9,8 +9,10 @@
 import org.openstreetmap.josm.data.coor.QuadTiling;
 import org.openstreetmap.josm.tools.Utils;
 
+/**
+ * A bounding box with latitude  / longitude coordinates
+ */
 public class BBox {
-
     private double xmin = Double.POSITIVE_INFINITY;
     private double xmax = Double.NEGATIVE_INFINITY;
     private double ymin = Double.POSITIVE_INFINITY;
@@ -17,6 +19,11 @@
     private double ymax = Double.NEGATIVE_INFINITY;
 
     /**
+     * Constructs a new (invalid) BBox
+     */
+    public BBox() { }
+
+    /**
      * Constructs a new {@code BBox} defined by a single point.
      *
      * @param x X coordinate
@@ -24,14 +31,18 @@
      * @since 6203
      */
     public BBox(final double x, final double y) {
-        xmax = xmin = x;
-        ymax = ymin = y;
-        sanity();
+        if (!Double.isNaN(x) && !Double.isNaN(y)) {
+            xmin = x;
+            ymin = y;
+            xmax = x;
+            ymax = y;
+            sanity();
+        }
     }
 
     /**
      * Constructs a new {@code BBox} defined by points <code>a</code> and <code>b</code>.
-     * Result is minimal BBox containing both points.
+     * Result is minimal BBox containing both points if they are both valid, else undefined
      *
      * @param a first point
      * @param b second point
@@ -52,7 +63,17 @@
         this.ymax = copy.ymax;
     }
 
+    /**
+     * Create minimal  BBox so that {@code this.bounds(ax,ay)} and {@code this.bounds(bx,by)} will both return true
+     * @param ax left or right X value (-180 .. 180)
+     * @param ay top or bottom Y value (-90 .. 90)
+     * @param bx left or right X value (-180 .. 180)
+     * @param by top or bottom Y value (-90 .. 90)
+     */
     public BBox(double ax, double ay, double bx, double by) {
+        if (Double.isNaN(ax) || Double.isNaN(ay) || Double.isNaN(bx) || Double.isNaN(by)) {
+            return; // use default which is an invalid BBox
+        }
 
         if (ax > bx) {
             xmax = ax;
@@ -69,47 +90,45 @@
             ymax = by;
             ymin = ay;
         }
-
         sanity();
     }
 
+    /**
+     * Create BBox for all nodes of the way with known coordinates.
+     * If no node has a known coordinate, an invalid BBox is returned.
+     * @param w the way
+     */
     public BBox(Way w) {
-        for (Node n : w.getNodes()) {
-            LatLon coor = n.getCoor();
-            if (coor == null) {
-                continue;
-            }
-            add(coor);
-        }
+        w.getNodes().forEach((n) -> add(n.getCoor()));
     }
 
+    /**
+     * Create BBox for a node. An invalid BBox is returned if the coordinates are not known.
+     * @param n the node
+     */
     public BBox(Node n) {
-        LatLon coor = n.getCoor();
-        if (coor == null) {
-            xmin = xmax = ymin = ymax = 0;
-        } else {
-            xmin = xmax = coor.lon();
-            ymin = ymax = coor.lat();
-        }
+        if (n.isLatLonKnown())
+            add(n.getCoor());
     }
 
+    /**
+     *
+     */
     private void sanity() {
-        if (xmin < -180.0) {
-            xmin = -180.0;
-        }
-        if (xmax > 180.0) {
-            xmax = 180.0;
-        }
-        if (ymin < -90.0) {
-            ymin = -90.0;
-        }
-        if (ymax > 90.0) {
-            ymax = 90.0;
-        }
+        xmin = Utils.clamp(xmin, -180, 180);
+        xmax = Utils.clamp(xmax, -180, 180);
+        ymin = Utils.clamp(ymin, -90, 90);
+        ymax = Utils.clamp(ymax, -90, 90);
     }
 
+    /**
+     * Add a point to an existing BBox. Extends this bbox if necessary so that this.bounds(c) will return true
+     * if c is a valid LatLon instance.
+     * @param c a LatLon point
+     */
     public final void add(LatLon c) {
-        add(c.lon(), c.lat());
+        if (c != null && c.isValid())
+            add(c.lon(), c.lat());
     }
 
     /**
@@ -118,6 +137,8 @@
      * @param y Y coordinate
      */
     public final void add(double x, double y) {
+        if (Double.isNaN(x) || Double.isNaN(y))
+            return;
         xmin = Math.min(xmin, x);
         xmax = Math.max(xmax, x);
         ymin = Math.min(ymin, y);
@@ -125,14 +146,25 @@
         sanity();
     }
 
-    public final void add(BBox box) {
-        xmin = Math.min(xmin, box.xmin);
-        xmax = Math.max(xmax, box.xmax);
-        ymin = Math.min(ymin, box.ymin);
-        ymax = Math.max(ymax, box.ymax);
-        sanity();
+    /**
+     * Extends this bbox to include the bbox other. Does nothing if other is not valid.
+     * @param other a bbox
+     */
+    public final void add(BBox other) {
+        if (other.isValid()) {
+            xmin = Math.min(xmin, other.xmin);
+            xmax = Math.max(xmax, other.xmax);
+            ymin = Math.min(ymin, other.ymin);
+            ymax = Math.max(ymax, other.ymax);
+            sanity();
+        }
     }
 
+    /**
+     * Extends this bbox to include the bbox of the primitive extended by extraSpace.
+     * @param primitive an OSM primitive
+     * @param extraSpace the value to extend the primitives bbox. Unit is in LatLon degrees.
+     */
     public void addPrimitive(OsmPrimitive primitive, double extraSpace) {
         BBox primBbox = primitive.getBBox();
         add(primBbox.xmin - extraSpace, primBbox.ymin - extraSpace);
@@ -278,6 +310,21 @@
             && Double.compare(b.xmin, xmin) == 0 && Double.compare(b.ymin, ymin) == 0;
     }
 
+    /**
+     * @return true if the bbox covers a part of the planets surface
+     * Height and width must be non-negative, but may (both) be 0.
+     */
+    public boolean isValid() {
+        return (xmin <= xmax && ymin <= ymax);
+    }
+
+    /**
+     * @return true if the bbox covers a part of the planets surface
+     */
+    public boolean isInWorld() {
+        return !(xmin < -180.0 || xmax > 180.0 || ymin < -90.0 || ymax > 90.0);
+    }
+
     @Override
     public String toString() {
         return "[ x: " + xmin + " -> " + xmax + ", y: " + ymin + " -> " + ymax + " ]";
Index: src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/DataSet.java	(working copy)
@@ -508,7 +508,9 @@
                 throw new DataIntegrityProblemException(
                         tr("Unable to add primitive {0} to the dataset because it is already included", primitive.toString()));
 
-            primitive.updatePosition(); // Set cached bbox for way and relation (required for reindexWay and reinexRelation to work properly)
+            allPrimitives.add(primitive);
+            primitive.setDataset(this);
+            primitive.updatePosition(); // Set cached bbox for way and relation (required for reindexWay and reindexRelation to work properly)
             boolean success = false;
             if (primitive instanceof Node) {
                 success = nodes.add((Node) primitive);
@@ -519,8 +521,6 @@
             }
             if (!success)
                 throw new RuntimeException("failed to add primitive: "+primitive);
-            allPrimitives.add(primitive);
-            primitive.setDataset(this);
             firePrimitivesAdded(Collections.singletonList(primitive), false);
         } finally {
             endUpdate();
Index: src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Node.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/Node.java	(working copy)
@@ -325,10 +325,15 @@
 
     @Override
     public BBox getBBox() {
-        return new BBox(this);
+        return new BBox(lon, lat);
     }
 
     @Override
+    protected void addToBBox(BBox box, Set<PrimitiveId> visited) {
+        box.add(lon, lat);
+    }
+
+    @Override
     public void updatePosition() {
         // Do nothing
     }
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(working copy)
@@ -1481,4 +1481,11 @@
     public boolean isMultipolygon() {
         return false;
     }
+
+    /**
+     * If necessary, extend the bbox to contain this primitive
+     * @param box a bbox instance
+     * @param visited a set of visited members  or null
+     */
+    protected abstract void addToBBox(BBox box, Set<PrimitiveId> visited);
 }
Index: src/org/openstreetmap/josm/data/osm/QuadBuckets.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/QuadBuckets.java	(working copy)
@@ -5,6 +5,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.NoSuchElementException;
 
@@ -31,7 +32,7 @@
         throw new AssertionError(s);
     }
 
-    public static final int MAX_OBJECTS_PER_LEVEL = 16;
+    private static final int MAX_OBJECTS_PER_LEVEL = 16;
 
     static class QBLevel<T extends OsmPrimitive> {
         private final int level;
@@ -181,11 +182,6 @@
         }
 
         boolean matches(final T o, final BBox searchBbox) {
-            if (o instanceof Node) {
-                final LatLon latLon = ((Node) o).getCoor();
-                // node without coords -> bbox[0,0,0,0]
-                return searchBbox.bounds(latLon != null ? latLon : LatLon.ZERO);
-            }
             return o.getBBox().intersects(searchBbox);
         }
 
@@ -393,6 +389,7 @@
     private QBLevel<T> root;
     private QBLevel<T> searchCache;
     private int size;
+    private Collection<T> invalidBBoxPrimitives;
 
     /**
      * Constructs a new {@code QuadBuckets}.
@@ -404,6 +401,7 @@
     @Override
     public final void clear() {
         root = new QBLevel<>(this);
+        invalidBBoxPrimitives = new LinkedHashSet<>();
         searchCache = null;
         size = 0;
     }
@@ -410,7 +408,10 @@
 
     @Override
     public boolean add(T n) {
-        root.add(n);
+        if (n.getBBox().isValid())
+            root.add(n);
+        else
+            invalidBBoxPrimitives.add(n);
         size++;
         return true;
     }
@@ -460,11 +461,12 @@
         T t = (T) o;
         searchCache = null; // Search cache might point to one of removed buckets
         QBLevel<T> bucket = root.findBucket(t.getBBox());
-        if (bucket.removeContent(t)) {
+        boolean removed = bucket.removeContent(t);
+        if (!removed)
+            removed = invalidBBoxPrimitives.remove(o);
+        if (removed)
             size--;
-            return true;
-        } else
-            return false;
+        return removed;
     }
 
     @Override
@@ -471,6 +473,8 @@
     public boolean contains(Object o) {
         @SuppressWarnings("unchecked")
         T t = (T) o;
+        if (!t.getBBox().isValid())
+            return invalidBBoxPrimitives.contains(o);
         QBLevel<T> bucket = root.findBucket(t.getBBox());
         return bucket != null && bucket.content != null && bucket.content.contains(t);
     }
@@ -501,6 +505,8 @@
         private QBLevel<T> currentNode;
         private int contentIndex;
         private int iteratedOver;
+        private Iterator<T> invalidBBoxIterator = invalidBBoxPrimitives.iterator();
+        boolean fromInvalidBBoxPrimitives;
         QuadBuckets<T> qb;
 
         final QBLevel<T> nextContentNode(QBLevel<T> q) {
@@ -527,8 +533,10 @@
 
         @Override
         public boolean hasNext() {
-            if (this.peek() == null)
-                return false;
+            if (this.peek() == null) {
+                fromInvalidBBoxPrimitives = true;
+                return invalidBBoxIterator.hasNext();
+            }
             return true;
         }
 
@@ -549,6 +557,8 @@
 
         @Override
         public T next() {
+            if (fromInvalidBBoxPrimitives)
+                return invalidBBoxIterator.next();
             T ret = peek();
             if (ret == null)
                 throw new NoSuchElementException();
@@ -559,14 +569,20 @@
 
         @Override
         public void remove() {
-            // two uses
-            // 1. Back up to the thing we just returned
-            // 2. move the index back since we removed
-            //    an element
-            contentIndex--;
-            T object = peek();
-            if (currentNode.removeContent(object))
+            if (fromInvalidBBoxPrimitives) {
+                invalidBBoxIterator.remove();
                 qb.size--;
+            } else {
+                // two uses
+                // 1. Back up to the thing we just returned
+                // 2. move the index back since we removed
+                //    an element
+                contentIndex--;
+                T object = peek();
+                if (currentNode.removeContent(object))
+                    qb.size--;
+
+            }
         }
     }
 
@@ -585,8 +601,16 @@
         return size == 0;
     }
 
+    /**
+     * Search for elements in the given bbox.
+     * @param searchBbox the bbox
+     * @return a list of elements, maybe empty but never null
+     */
     public List<T> search(BBox searchBbox) {
         List<T> ret = new ArrayList<>();
+        if (!searchBbox.isValid()) {
+            return ret;
+        }
         // Doing this cuts down search cost on a real-life data set by about 25%
         if (searchCache == null) {
             searchCache = root;
Index: src/org/openstreetmap/josm/data/osm/Relation.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Relation.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/Relation.java	(working copy)
@@ -427,50 +427,28 @@
 
     @Override
     public BBox getBBox() {
-        RelationMember[] members = this.members;
+        if (getDataSet() != null && bbox != null)
+            return new BBox(bbox); // use cached value
 
-        if (members.length == 0)
-            return new BBox(0, 0, 0, 0);
-        if (getDataSet() == null)
-            return calculateBBox(new HashSet<PrimitiveId>());
-        else {
-            if (bbox == null) {
-                bbox = calculateBBox(new HashSet<PrimitiveId>());
-            }
-            if (bbox == null)
-                return new BBox(0, 0, 0, 0); // No real members
-            else
-                return new BBox(bbox);
-        }
+        BBox box = new BBox();
+        addToBBox(box, new HashSet<PrimitiveId>());
+        if (getDataSet() != null)
+            bbox = box; // set cache
+        return new BBox(box);
     }
 
-    private BBox calculateBBox(Set<PrimitiveId> visitedRelations) {
-        if (visitedRelations.contains(this))
-            return null;
-        visitedRelations.add(this);
-
-        RelationMember[] members = this.members;
-        if (members.length == 0)
-            return null;
-        else {
-            BBox result = null;
-            for (RelationMember rm:members) {
-                BBox box = rm.isRelation() ? rm.getRelation().calculateBBox(visitedRelations) : rm.getMember().getBBox();
-                if (box != null) {
-                    if (result == null) {
-                        result = box;
-                    } else {
-                        result.add(box);
-                    }
-                }
-            }
-            return result;
+    @Override
+    protected void addToBBox(BBox box, Set<PrimitiveId> visited) {
+        for (RelationMember rm : members) {
+            if (visited.add(rm.getMember()))
+                rm.getMember().addToBBox(box, visited);
         }
     }
 
     @Override
     public void updatePosition() {
-        bbox = calculateBBox(new HashSet<PrimitiveId>());
+        bbox = null; // make sure that it is recalculated
+        bbox = getBBox();
     }
 
     @Override
Index: src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/Way.java	(revision 10912)
+++ src/org/openstreetmap/josm/data/osm/Way.java	(working copy)
@@ -633,6 +633,11 @@
     }
 
     @Override
+    protected void addToBBox(BBox box, Set<PrimitiveId> visited) {
+        box.add(getBBox());
+    }
+
+    @Override
     public void updatePosition() {
         bbox = new BBox(this);
     }
Index: test/unit/org/openstreetmap/josm/data/osm/BBoxTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/BBoxTest.java	(revision 10912)
+++ test/unit/org/openstreetmap/josm/data/osm/BBoxTest.java	(working copy)
@@ -1,13 +1,16 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.data.coor.LatLon;
 
 import nl.jqno.equalsverifier.EqualsVerifier;
 import nl.jqno.equalsverifier.Warning;
-
 /**
  * Unit tests for class {@link BBox}.
  */
@@ -30,4 +33,31 @@
             .suppress(Warning.NONFINAL_FIELDS)
             .verify();
     }
+
+    @Test
+    public void testLatLonConstructor() {
+        LatLon latLon1 = new LatLon(10, 20);
+        LatLon latLon2 = new LatLon(20, 10);
+        BBox b1 = new BBox(latLon1, latLon2);
+        BBox b2 = new BBox(latLon2, latLon1);
+        assertTrue(b1.bounds(latLon1));
+        assertTrue(b2.bounds(latLon1));
+        assertTrue(b1.bounds(latLon2));
+        assertTrue(b2.bounds(latLon2));
+        assertTrue(b2.bounds(b1));
+        assertTrue(b1.bounds(b2));
+
+        // invalid latlon values
+        LatLon invalid1 = new LatLon(-190, 340);
+        BBox b3 = new BBox(invalid1, latLon1);
+        BBox b4 = new BBox(latLon1, invalid1);
+        BBox b5 = new BBox(invalid1, invalid1);
+        // what should be the result?
+        assertTrue(b3.isValid());
+        assertTrue(b4.isValid());
+        assertTrue(b3.bounds(latLon1));
+        assertTrue(b4.bounds(latLon1));
+        assertFalse(b5.isValid());
+    }
+
 }
Index: test/unit/org/openstreetmap/josm/data/osm/NodeTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/NodeTest.java	(revision 10912)
+++ test/unit/org/openstreetmap/josm/data/osm/NodeTest.java	(working copy)
@@ -1,9 +1,11 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -41,4 +43,39 @@
         assertNull(n.getCoor());
         assertFalse(n.isOutsideDownloadArea());
     }
+
+    /**
+     * Test BBox calculation with Node
+     */
+    @Test
+    public void testBBox() {
+        DataSet ds = new DataSet();
+        Node n1 = new Node(1);
+        Node n2 = new Node(2);
+        Node n3 = new Node(3);
+        Node n4 = new Node(4);
+        n1.setIncomplete(true);
+        n2.setCoor(new LatLon(10, 10));
+        n3.setCoor(new LatLon(20, 20));
+        n4.setCoor(new LatLon(90, 180));
+        ds.addPrimitive(n1);
+        ds.addPrimitive(n2);
+        ds.addPrimitive(n3);
+        ds.addPrimitive(n4);
+
+        assertFalse(n1.getBBox().isValid());
+        assertTrue(n2.getBBox().isValid());
+        assertTrue(n3.getBBox().isValid());
+        assertTrue(n4.getBBox().isValid());
+        BBox box1 = n1.getBBox();
+        box1.add(n2.getCoor());
+        assertTrue(box1.isValid());
+        BBox box2 = n2.getBBox();
+        box2.add(n1.getCoor());
+        assertTrue(box2.isValid());
+        assertEquals(box1, box2);
+        box1.add(n3.getCoor());
+        assertTrue(box1.isValid());
+        assertEquals(box1.getCenter(), new LatLon(15, 15));
+    }
 }
Index: test/unit/org/openstreetmap/josm/data/osm/QuadBucketsTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/QuadBucketsTest.java	(revision 10912)
+++ test/unit/org/openstreetmap/josm/data/osm/QuadBucketsTest.java	(working copy)
@@ -8,6 +8,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Random;
 
 import org.fest.reflect.core.Reflection;
 import org.fest.reflect.reference.TypeRef;
@@ -173,5 +174,80 @@
             Assert.assertEquals(count, qbWays.size());
         }
         Assert.assertEquals(0, qbWays.size());
+
     }
+
+    /**
+     *  Add more data so that quad buckets tree has a few leaves
+     */
+    @Test
+    public void testSplitsWithIncompleteData() {
+        DataSet ds = new DataSet();
+        long nodeId = 1;
+        long wayId = 1;
+        final int NUM_COMPLETE_WAYS = 300;
+        final int NUM_INCOMPLETE_WAYS = 10;
+        final int NUM_NODES_PER_WAY = 20;
+        final int NUM_INCOMPLETE_NODES = 10;
+
+        // force splits in quad buckets
+        Random random = new Random(31);
+        for (int i = 0; i < NUM_COMPLETE_WAYS; i++) {
+            Way w = new Way(wayId++);
+            List<Node> nodes = new ArrayList<>();
+            double center = random.nextDouble() * 10;
+            for (int j = 0; j < NUM_NODES_PER_WAY; j++) {
+                Node n = new Node(nodeId++);
+                double lat = random.nextDouble() * 0.001;
+                double lon = random.nextDouble() * 0.001;
+                n.setCoor(new LatLon(center + lat, center + lon));
+                nodes.add(n);
+                ds.addPrimitive(n);
+            }
+            w.setNodes(nodes);
+            ds.addPrimitive(w);
+        }
+        Assert.assertEquals(NUM_COMPLETE_WAYS, ds.getWays().size());
+        Assert.assertEquals(NUM_COMPLETE_WAYS * NUM_NODES_PER_WAY, ds.getNodes().size());
+
+        // add some incomplete nodes
+        List<Node> incompleteNodes = new ArrayList<>();
+        for (int i = 0; i < NUM_INCOMPLETE_NODES; i++) {
+            Node n = new Node(nodeId++);
+            incompleteNodes.add(n);
+            n.setIncomplete(true);
+            ds.addPrimitive(n);
+        }
+        Assert.assertEquals(NUM_COMPLETE_WAYS * NUM_NODES_PER_WAY + NUM_INCOMPLETE_NODES, ds.getNodes().size());
+        // add some incomplete ways
+        List<Way> incompleteWays = new ArrayList<>();
+        for (int i = 0; i < NUM_INCOMPLETE_WAYS; i++) {
+            Way w = new Way(wayId++);
+            incompleteWays.add(w);
+            w.setIncomplete(true);
+            ds.addPrimitive(w);
+        }
+        Assert.assertEquals(NUM_COMPLETE_WAYS + NUM_INCOMPLETE_WAYS, ds.getWays().size());
+
+        BBox planet = new BBox(-180, -90, 180, 90);
+        // incomplete ways should not be found with search
+        Assert.assertEquals(NUM_COMPLETE_WAYS, ds.searchWays(planet).size());
+        // incomplete ways are only retrieved via iterator or object reference
+        for (Way w : incompleteWays) {
+            Assert.assertTrue(ds.getWays().contains(w));
+        }
+
+        QuadBuckets<Way> qb = new QuadBuckets<>();
+        qb.addAll(ds.getWays());
+        int count = qb.size();
+        Assert.assertEquals(count, ds.getWays().size());
+        Iterator<Way> iter = qb.iterator();
+        while (iter.hasNext()) {
+            iter.next();
+            iter.remove();
+            count--;
+            Assert.assertEquals(count, qb.size());
+        }
+        Assert.assertEquals(0, qb.size());
+    }
 }
Index: test/unit/org/openstreetmap/josm/data/osm/RelationTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/RelationTest.java	(revision 10912)
+++ test/unit/org/openstreetmap/josm/data/osm/RelationTest.java	(working copy)
@@ -74,6 +74,15 @@
         w1.addNode(n3);
         Assert.assertEquals(w1.getBBox(), r1.getBBox());
         Assert.assertEquals(w1.getBBox(), r2.getBBox());
+
+        // create incomplete node and add it to the relation, this must not change the bbox
+        BBox oldBBox = r2.getBBox();
+        Node n4 = new Node();
+        n4.setIncomplete(true);
+        ds.addPrimitive(n4);
+        r2.addMember(new RelationMember("", n4));
+
+        Assert.assertEquals(oldBBox, r2.getBBox());
     }
 
     @Test
Index: test/unit/org/openstreetmap/josm/data/osm/WayTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/WayTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/data/osm/WayTest.java	(working copy)
@@ -0,0 +1,56 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+/**
+ * Unit tests of the {@code Node} class.
+ */
+public class WayTest {
+
+    /**
+     * Setup test.
+     */
+    @BeforeClass
+    public static void setUpBeforeClass() {
+        JOSMFixture.createUnitTestFixture().init();
+    }
+
+    /**
+     * Test BBox calculation with Way
+     */
+    @Test
+    public void testBBox() {
+        DataSet ds = new DataSet();
+        Node n1 = new Node(1);
+        Node n2 = new Node(2);
+        Node n3 = new Node(3);
+        Node n4 = new Node(4);
+        n1.setIncomplete(true);
+        n2.setCoor(new LatLon(10, 10));
+        n3.setCoor(new LatLon(20, 20));
+        n4.setCoor(new LatLon(90, 180));
+        ds.addPrimitive(n1);
+        ds.addPrimitive(n2);
+        ds.addPrimitive(n3);
+        ds.addPrimitive(n4);
+        Way way = new Way(1);
+        assertFalse(way.getBBox().isValid());
+        way.setNodes(Arrays.asList(n1));
+        assertFalse(way.getBBox().isValid());
+        way.setNodes(Arrays.asList(n2));
+        assertTrue(way.getBBox().isValid());
+        way.setNodes(Arrays.asList(n1, n2));
+        assertTrue(way.getBBox().isValid());
+        assertEquals(way.getBBox(), new BBox(10, 10));
+    }
+}
