Index: trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/AddNodeAction.java	(revision 18494)
@@ -75,5 +75,5 @@
             ds.setSelected(nnew);
             MapView mapView = MainApplication.getMap().mapView;
-            if (mapView != null && !mapView.getRealBounds().contains(nnew.getCoor())) {
+            if (mapView != null && !mapView.getRealBounds().contains(nnew)) {
                 AutoScaleAction.zoomTo(Collections.<OsmPrimitive>singleton(nnew));
             }
Index: trunk/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/CopyCoordinatesAction.java	(revision 18494)
@@ -40,5 +40,4 @@
         ICoordinateFormat coordinateFormat = CoordinateFormatManager.getDefaultFormat();
         String string = getSelectedNodes().stream()
-                .map(Node::getCoor)
                 .filter(Objects::nonNull)
                 .map(c -> coordinateFormat.toString(c, ", "))
Index: trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/CreateCircleAction.java	(revision 18494)
@@ -192,8 +192,7 @@
 
         // see #10777
-        LatLon ll1 = ProjectionRegistry.getProjection().eastNorth2latlon(n1);
         LatLon ll2 = ProjectionRegistry.getProjection().eastNorth2latlon(center);
 
-        double radiusInMeters = ll1.greatCircleDistance(ll2);
+        double radiusInMeters = nodes.get(0).greatCircleDistance(ll2);
 
         int numberOfNodesInCircle = (int) Math.ceil(6.0 * Math.pow(radiusInMeters, 0.5));
Index: trunk/src/org/openstreetmap/josm/actions/DownloadAlongAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DownloadAlongAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/DownloadAlongAction.java	(revision 18494)
@@ -23,4 +23,5 @@
 
 import org.openstreetmap.josm.actions.downloadtasks.DownloadTaskList;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -161,6 +162,6 @@
         ArrayList<LatLon> intermediateNodes = new ArrayList<>();
         intermediateNodes.add(p2);
-        if (p1 != null && p2.greatCircleDistance(p1) > bufferDist) {
-            double d = p2.greatCircleDistance(p1) / bufferDist;
+        if (p1 != null && p2.greatCircleDistance((ILatLon) p1) > bufferDist) {
+            double d = p2.greatCircleDistance((ILatLon) p1) / bufferDist;
             int nbNodes = (int) d;
             if (Logging.isDebugEnabled()) {
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DrawSnapHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DrawSnapHelper.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DrawSnapHelper.java	(revision 18494)
@@ -389,5 +389,5 @@
         // find out the distance, in metres, between the base point and projected point
         LatLon mouseLatLon = mapView.getProjection().eastNorth2latlon(snapPoint);
-        double distance = this.drawAction.getCurrentBaseNode().getCoor().greatCircleDistance(mouseLatLon);
+        double distance = this.drawAction.getCurrentBaseNode().greatCircleDistance(mouseLatLon);
         double hdg = Utils.toDegrees(p0.heading(snapPoint));
         // heading of segment from current to calculated point, not to mouse position
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ExtrudeAction.java	(revision 18494)
@@ -38,4 +38,5 @@
 import org.openstreetmap.josm.data.UndoRedoHandler;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.osm.DataIntegrityProblemException;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -938,5 +939,5 @@
         // find out the movement distance, in metres
         double distance = ProjectionRegistry.getProjection().eastNorth2latlon(initialN1en).greatCircleDistance(
-                ProjectionRegistry.getProjection().eastNorth2latlon(n1movedEn));
+                (ILatLon) ProjectionRegistry.getProjection().eastNorth2latlon(n1movedEn));
         MainApplication.getMap().statusLine.setDist(distance);
         updateStatusLine();
Index: trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/ParallelWayAction.java	(revision 18494)
@@ -28,4 +28,5 @@
 import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -392,5 +393,6 @@
         // Note: d is the distance in _projected units_
         double d = enp.distance(nearestPointOnRefLine);
-        double realD = mv.getProjection().eastNorth2latlon(enp).greatCircleDistance(mv.getProjection().eastNorth2latlon(nearestPointOnRefLine));
+        double realD = mv.getProjection().eastNorth2latlon(enp).greatCircleDistance(
+                (ILatLon) mv.getProjection().eastNorth2latlon(nearestPointOnRefLine));
         double snappedRealD = realD;
 
Index: trunk/src/org/openstreetmap/josm/command/MoveCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/command/MoveCommand.java	(revision 18494)
@@ -16,4 +16,5 @@
 
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -314,10 +315,10 @@
         return nodes.stream()
                 .filter(predicate)
-                .filter(node -> node.getCoor() != null && node.getEastNorth() != null)
+                .filter(ILatLon::isLatLonKnown /* If the node latlon is known, then the eastnorth cannot be null */)
                 .findFirst()
                 .map(node -> {
                     final Node old = new Node(node);
                     old.setEastNorth(old.getEastNorth().add(-x, -y));
-                    return node.getCoor().greatCircleDistance(old.getCoor());
+                    return node.greatCircleDistance(old);
                 }).orElse(Double.NaN);
     }
Index: trunk/src/org/openstreetmap/josm/data/coor/ILatLon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/ILatLon.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/coor/ILatLon.java	(revision 18494)
@@ -2,5 +2,15 @@
 package org.openstreetmap.josm.data.coor;
 
+import static java.lang.Math.PI;
+import static java.lang.Math.asin;
+import static java.lang.Math.atan2;
+import static java.lang.Math.cos;
+import static java.lang.Math.sin;
+import static java.lang.Math.sqrt;
+import static org.openstreetmap.josm.data.projection.Ellipsoid.WGS84;
+import static org.openstreetmap.josm.tools.Utils.toRadians;
+
 import org.openstreetmap.josm.data.projection.Projecting;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -81,3 +91,56 @@
         return Math.abs(lat() - other.lat()) <= p && Math.abs(lon() - other.lon()) <= p;
     }
+
+    /**
+     * Computes the distance between this lat/lon and another point on the earth.
+     * Uses <a href="https://en.wikipedia.org/wiki/Haversine_formula">Haversine formula</a>.
+     * @param other the other point.
+     * @return distance in metres.
+     * @since xxx (extracted from {@link LatLon})
+     */
+    default double greatCircleDistance(ILatLon other) {
+        double sinHalfLat = sin(toRadians(other.lat() - this.lat()) / 2);
+        double sinHalfLon = sin(toRadians(other.lon() - this.lon()) / 2);
+        double d = 2 * WGS84.a * asin(
+                sqrt(sinHalfLat*sinHalfLat +
+                        cos(toRadians(this.lat()))*cos(toRadians(other.lat()))*sinHalfLon*sinHalfLon));
+        // For points opposite to each other on the sphere,
+        // rounding errors could make the argument of asin greater than 1
+        // (This should almost never happen.)
+        if (Double.isNaN(d)) {
+            Logging.error("NaN in greatCircleDistance: {0} {1}", this, other);
+            d = PI * WGS84.a;
+        }
+        return d;
+    }
+
+    /**
+     * Returns bearing from this point to another.
+     *
+     * Angle starts from north and increases clockwise, PI/2 means east.
+     *
+     * Please note that reverse bearing (from other point to this point) should NOT be
+     * calculated from return value of this method, because great circle path
+     * between the two points have different bearings at each position.
+     *
+     * To get bearing from another point to this point call other.bearing(this)
+     *
+     * @param other the "destination" position
+     * @return heading in radians in the range 0 &lt;= hd &lt; 2*PI
+     * @since xxx (extracted from {@link LatLon}, added in 9796)
+     */
+    default double bearing(ILatLon other) {
+        double lat1 = toRadians(this.lat());
+        double lat2 = toRadians(other.lat());
+        double dlon = toRadians(other.lon() - this.lon());
+        double bearing = atan2(
+                sin(dlon) * cos(lat2),
+                cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon)
+        );
+        bearing %= 2 * PI;
+        if (bearing < 0) {
+            bearing += 2 * PI;
+        }
+        return bearing;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/data/coor/LatLon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/coor/LatLon.java	(revision 18494)
@@ -1,13 +1,4 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.coor;
-
-import static java.lang.Math.PI;
-import static java.lang.Math.asin;
-import static java.lang.Math.atan2;
-import static java.lang.Math.cos;
-import static java.lang.Math.sin;
-import static java.lang.Math.sqrt;
-import static org.openstreetmap.josm.data.projection.Ellipsoid.WGS84;
-import static org.openstreetmap.josm.tools.Utils.toRadians;
 
 import java.awt.geom.Area;
@@ -20,5 +11,4 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
-import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -229,19 +219,9 @@
      * @param other the other point.
      * @return distance in metres.
-     */
+     * @deprecated since xxx (use {@link ILatLon#greatCircleDistance(ILatLon)} instead)
+     */
+    @Deprecated
     public double greatCircleDistance(LatLon other) {
-        double sinHalfLat = sin(toRadians(other.lat() - this.lat()) / 2);
-        double sinHalfLon = sin(toRadians(other.lon() - this.lon()) / 2);
-        double d = 2 * WGS84.a * asin(
-                sqrt(sinHalfLat*sinHalfLat +
-                        cos(toRadians(this.lat()))*cos(toRadians(other.lat()))*sinHalfLon*sinHalfLon));
-        // For points opposite to each other on the sphere,
-        // rounding errors could make the argument of asin greater than 1
-        // (This should almost never happen.)
-        if (Double.isNaN(d)) {
-            Logging.error("NaN in greatCircleDistance: {0} {1}", this, other);
-            d = PI * WGS84.a;
-        }
-        return d;
+        return ILatLon.super.greatCircleDistance(other);
     }
 
@@ -260,18 +240,9 @@
      * @return heading in radians in the range 0 &lt;= hd &lt; 2*PI
      * @since 9796
-     */
+     * @deprecated since xxx (use {@link ILatLon#bearing(ILatLon)} instead)
+     */
+    @Deprecated
     public double bearing(LatLon other) {
-        double lat1 = toRadians(this.lat());
-        double lat2 = toRadians(other.lat());
-        double dlon = toRadians(other.lon() - this.lon());
-        double bearing = atan2(
-            sin(dlon) * cos(lat2),
-            cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon)
-        );
-        bearing %= 2 * PI;
-        if (bearing < 0) {
-            bearing += 2 * PI;
-        }
-        return bearing;
+        return ILatLon.super.bearing(other);
     }
 
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 18494)
@@ -7,4 +7,5 @@
 import java.util.concurrent.TimeUnit;
 
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -92,5 +93,5 @@
                             List<Pair<Double, WayPoint>> nextWps = new ArrayList<>();
                             for (int j = i; j < size; j++) {
-                                totalDist += wps.get(j - 1).getCoor().greatCircleDistance(wps.get(j).getCoor());
+                                totalDist += wps.get(j - 1).greatCircleDistance(wps.get(j));
                                 nextWps.add(new Pair<>(totalDist, wps.get(j)));
                                 if (wps.get(j).hasDate()) {
@@ -121,5 +122,5 @@
                             if (!trkInt || isFirst || prevWp == null ||
                                     Math.abs(curWpTime - prevWpTime) > TimeUnit.MINUTES.toMillis(trkTime) ||
-                                    prevWp.getCoor().greatCircleDistance(curWp.getCoor()) > trkDist) {
+                                    prevWp.greatCircleDistance(curWp) > trkDist) {
                                 isFirst = false;
                                 interpolate = false;
@@ -132,5 +133,5 @@
                             if (!segInt || prevWp == null ||
                                     Math.abs(curWpTime - prevWpTime) > TimeUnit.MINUTES.toMillis(segTime) ||
-                                    prevWp.getCoor().greatCircleDistance(curWp.getCoor()) > segDist) {
+                                    prevWp.greatCircleDistance(curWp) > segDist) {
                                 interpolate = false;
                                 if (segTag) {
@@ -238,5 +239,5 @@
 
         if (prevWp != null && interpolate) {
-            double distance = prevWp.getCoor().greatCircleDistance(curWp.getCoor());
+            double distance = prevWp.greatCircleDistance(curWp);
             // This is in km/h, 3.6 * m/s
             if (curWpTime > prevWpTime) {
@@ -267,5 +268,5 @@
                     }
                     if (nextWp != null && dirpos.isSetImageDirection()) {
-                        double direction = curWp.getCoor().bearing(nextWp.getCoor());
+                        double direction = curWp.bearing(nextWp);
                         curTmp.setExifImgDir(computeDirection(direction, dirpos.getImageDirectionAngleOffset()));
                     }
@@ -298,5 +299,5 @@
                     LatLon position = prevCoor.interpolate(curCoor, timeDiff);
                     if (nextCoorForDirection != null && (shiftXY || dirpos.isSetImageDirection())) {
-                        double direction = position.bearing(nextCoorForDirection);
+                        double direction = position.bearing((ILatLon) nextCoorForDirection);
                         if (dirpos.isSetImageDirection()) {
                             curTmp.setExifImgDir(computeDirection(direction, dirpos.getImageDirectionAngleOffset()));
@@ -307,5 +308,5 @@
                             final double offsetY = dirpos.getShiftImageY();
                             final double r = Math.sqrt(offsetX * offsetX + offsetY * offsetY);
-                            final double orientation = (direction + LatLon.ZERO.bearing(new LatLon(offsetX, offsetY))) % (2 * Math.PI);
+                            final double orientation = (direction + LatLon.ZERO.bearing((ILatLon) new LatLon(offsetX, offsetY))) % (2 * Math.PI);
                             position = proj.eastNorth2latlon(proj.latlon2eastNorth(position)
                                     .add(r * Math.sin(orientation), r * Math.cos(orientation)));
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxTrackSegment.java	(revision 18494)
@@ -47,5 +47,5 @@
         for (WayPoint tpt : wayPoints) {
             if (last != null) {
-                Double d = last.getCoor().greatCircleDistance(tpt.getCoor());
+                Double d = last.greatCircleDistance(tpt);
                 if (!d.isNaN() && !d.isInfinite()) {
                     result += d;
Index: trunk/src/org/openstreetmap/josm/data/osm/Node.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/osm/Node.java	(revision 18494)
@@ -373,11 +373,10 @@
      */
     public boolean isOutSideWorld() {
-        LatLon ll = getCoor();
-        if (ll != null) {
+        if (this.isLatLonKnown()) {
             Bounds b = ProjectionRegistry.getProjection().getWorldBoundsLatLon();
             if (lat() < b.getMinLat() || lat() > b.getMaxLat() || lon() < b.getMinLon() || lon() > b.getMaxLon()) {
                 return true;
             }
-            if (!ProjectionRegistry.getProjection().latlon2eastNorth(ll).equalsEpsilon(getEastNorth(), 1.0)) {
+            if (!ProjectionRegistry.getProjection().latlon2eastNorth(this).equalsEpsilon(getEastNorth(), 1.0)) {
                 // we get here if a node was moved or created left from -180 or right from +180
                 return true;
Index: trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 18494)
@@ -13,5 +13,5 @@
 import java.util.stream.IntStream;
 
-import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
 import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
@@ -632,5 +632,5 @@
 
     /**
-     * Replies the length of the way, in metres, as computed by {@link LatLon#greatCircleDistance}.
+     * Replies the length of the way, in metres, as computed by {@link ILatLon#greatCircleDistance}.
      * @return The length of the way, in metres
      * @since 4138
@@ -640,10 +640,6 @@
         Node lastN = null;
         for (Node n:nodes) {
-            if (lastN != null) {
-                LatLon lastNcoor = lastN.getCoor();
-                LatLon coor = n.getCoor();
-                if (lastNcoor != null && coor != null) {
-                    length += coor.greatCircleDistance(lastNcoor);
-                }
+            if (lastN != null && lastN.isLatLonKnown() && n.isLatLonKnown()) {
+                length += n.greatCircleDistance(lastN);
             }
             lastN = n;
@@ -653,5 +649,5 @@
 
     /**
-     * Replies the length of the longest segment of the way, in metres, as computed by {@link LatLon#greatCircleDistance}.
+     * Replies the length of the longest segment of the way, in metres, as computed by {@link ILatLon#greatCircleDistance}.
      * @return The length of the segment, in metres
      * @since 8320
@@ -661,12 +657,8 @@
         Node lastN = null;
         for (Node n:nodes) {
-            if (lastN != null) {
-                LatLon lastNcoor = lastN.getCoor();
-                LatLon coor = n.getCoor();
-                if (lastNcoor != null && coor != null) {
-                    double l = coor.greatCircleDistance(lastNcoor);
-                    if (l > length) {
-                        length = l;
-                    }
+            if (lastN != null && lastN.isLatLonKnown() && n.isLatLonKnown()) {
+                double l = n.greatCircleDistance(lastN);
+                if (l > length) {
+                    length = l;
                 }
             }
Index: trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 18494)
@@ -29,5 +29,4 @@
 
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -1809,7 +1808,6 @@
                 return false;
             else if (osm instanceof Node) {
-                LatLon coordinate = ((Node) osm).getCoor();
                 Collection<Bounds> allBounds = getBounds(osm);
-                return coordinate != null && allBounds != null && allBounds.stream().anyMatch(bounds -> bounds.contains(coordinate));
+                return ((Node) osm).isLatLonKnown() && allBounds != null && allBounds.stream().anyMatch(bounds -> bounds.contains((Node) osm));
             } else if (osm instanceof Way) {
                 Collection<Node> nodes = ((Way) osm).getNodes();
Index: trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/projection/CustomProjection.java	(revision 18494)
@@ -19,4 +19,5 @@
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.conversion.LatLonParser;
@@ -808,5 +809,5 @@
                         // project back and check if the result is somewhat reasonable
                         LatLon llBack = eastNorth2latlon(enPole);
-                        if (llBack.isValid() && ll.greatCircleDistance(llBack) < 1000) {
+                        if (llBack.isValid() && ll.greatCircleDistance((ILatLon) llBack) < 1000) {
                             polesEN.put(p, enPole);
                         }
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/Addresses.java	(revision 18494)
@@ -23,4 +23,5 @@
 import org.openstreetmap.josm.command.DeleteCommand;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
@@ -362,6 +363,9 @@
      */
     static double getDistance(OsmPrimitive a, OsmPrimitive b) {
-        LatLon centerA = a.getBBox().getCenter();
-        LatLon centerB = b.getBBox().getCenter();
+        if (a instanceof ILatLon && b instanceof ILatLon) {
+            return ((ILatLon) a).greatCircleDistance((ILatLon) b);
+        }
+        ILatLon centerA = a.getBBox().getCenter();
+        ILatLon centerB = b.getBBox().getCenter();
         return centerA.greatCircleDistance(centerB);
     }
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/LongSegment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/LongSegment.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/LongSegment.java	(revision 18494)
@@ -9,5 +9,4 @@
 import java.util.Set;
 
-import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -92,9 +91,9 @@
 
     private void visitWaySegment(Way w, int i) {
-        LatLon coor1 = w.getNode(i).getCoor();
-        LatLon coor2 = w.getNode(i + 1).getCoor();
+        Node oneI = w.getNode(i);
+        Node twoI = w.getNode(i + 1);
 
-        if (coor1 != null && coor2 != null) {
-            Double length = coor1.greatCircleDistance(coor2);
+        if (oneI.isLatLonKnown() && twoI.isLatLonKnown()) {
+            double length = oneI.greatCircleDistance(twoI);
             if (length > maxlength) {
                 addErrorForSegment(new WaySegment(w, i), length / 1000.0);
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/UnconnectedWays.java	(revision 18494)
@@ -469,5 +469,5 @@
                 LatLon cl = ProjectionRegistry.getProjection().eastNorth2latlon(calcClosest(uncon));
                 // calculate real detour length, closest point might be somewhere between n1 and n2
-                double detourLen = len + node.getCoor().greatCircleDistance(cl);
+                double detourLen = len + node.greatCircleDistance(cl);
                 if (detourLen > maxLen)
                     return false;
@@ -501,5 +501,5 @@
                         visited.add(next);
                         if (!containsN && isConnectedTo(next, visited,
-                                len + node.getCoor().greatCircleDistance(next.getCoor()), way)) {
+                                len + node.greatCircleDistance(next), way)) {
                             return true;
                         }
@@ -516,5 +516,5 @@
         double getDist(Node n) {
             EastNorth closest = calcClosest(n);
-            return n.getCoor().greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(closest));
+            return n.greatCircleDistance(ProjectionRegistry.getProjection().eastNorth2latlon(closest));
         }
 
@@ -527,6 +527,6 @@
 
         private BBox getBounds(double fudge) {
-            double x1 = n1.getCoor().lon();
-            double x2 = n2.getCoor().lon();
+            double x1 = n1.lon();
+            double x2 = n2.lon();
             if (x1 > x2) {
                 double tmpx = x1;
@@ -534,6 +534,6 @@
                 x2 = tmpx;
             }
-            double y1 = n1.getCoor().lat();
-            double y2 = n2.getCoor().lat();
+            double y1 = n1.lat();
+            double y2 = n2.lat();
             if (y1 > y2) {
                 double tmpy = y1;
Index: trunk/src/org/openstreetmap/josm/gui/MapStatus.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/MapStatus.java	(revision 18494)
@@ -62,4 +62,5 @@
 import org.openstreetmap.josm.data.SystemOfMeasurement;
 import org.openstreetmap.josm.data.SystemOfMeasurement.SoMChangeListener;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.conversion.CoordinateFormatManager;
@@ -71,5 +72,4 @@
 import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
 import org.openstreetmap.josm.data.osm.IPrimitive;
-import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Way;
@@ -1221,11 +1221,7 @@
             OsmPrimitive n2 = it.next();
             // show distance between two selected nodes with coordinates
-            if (n1 instanceof Node && n2 instanceof Node) {
-                LatLon c1 = ((Node) n1).getCoor();
-                LatLon c2 = ((Node) n2).getCoor();
-                if (c1 != null && c2 != null) {
-                    setDist(c1.greatCircleDistance(c2));
-                    return;
-                }
+            if (n1 instanceof ILatLon && n2 instanceof ILatLon && ((ILatLon) n1).isLatLonKnown() && ((ILatLon) n2).isLatLonKnown()) {
+                setDist(((ILatLon) n1).greatCircleDistance((ILatLon) n2));
+                return;
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java	(revision 18494)
@@ -399,6 +399,6 @@
         int w = getWidth()/2;
         int h = getHeight()/2;
-        LatLon ll1 = getLatLon(w-50, h);
-        LatLon ll2 = getLatLon(w+50, h);
+        ILatLon ll1 = getLatLon(w-50, h);
+        ILatLon ll2 = getLatLon(w+50, h);
         double gcd = ll1.greatCircleDistance(ll2);
         if (alwaysPositive && gcd <= 0)
@@ -649,5 +649,5 @@
         LatLon ll2 = getLatLon(width / 2 + 50, height / 2);
         if (ll1.isValid() && ll2.isValid() && b.contains(ll1) && b.contains(ll2)) {
-            double dm = ll1.greatCircleDistance(ll2);
+            double dm = ll1.greatCircleDistance((ILatLon) ll2);
             double den = 100 * getScale();
             double scaleMin = 0.01 * den / dm / 100;
Index: trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java	(revision 18494)
@@ -29,4 +29,5 @@
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.BBox;
@@ -168,6 +169,6 @@
         ICoordinate c1 = getPosition(w - 50, h);
         ICoordinate c2 = getPosition(w + 50, h);
-        final LatLon ll1 = new LatLon(c1.getLat(), c1.getLon());
-        final LatLon ll2 = new LatLon(c2.getLat(), c2.getLon());
+        final ILatLon ll1 = new LatLon(c1.getLat(), c1.getLon());
+        final ILatLon ll2 = new LatLon(c2.getLat(), c2.getLon());
         double gcd = ll1.greatCircleDistance(ll2);
         return gcd <= 0 ? 0.1 : gcd;
Index: trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/history/CoordinateInfoViewer.java	(revision 18494)
@@ -1,4 +1,5 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.history;
+
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -24,4 +25,5 @@
 import org.openstreetmap.josm.command.MoveCommand;
 import org.openstreetmap.josm.data.UndoRedoHandler;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.conversion.DecimalDegreesCoordinateFormat;
@@ -408,6 +410,6 @@
             final Pair<LatLon, LatLon> coordinates = updater.getCoordinates();
             if (coordinates == null) return;
-            final LatLon coord = coordinates.a;
-            final LatLon oppositeCoord = coordinates.b;
+            final ILatLon coord = coordinates.a;
+            final ILatLon oppositeCoord = coordinates.b;
 
             // update distance
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 18494)
@@ -567,5 +567,5 @@
                         }
                         if (oldWp != null && trkPnt.getTimeInMillis() > oldWp.getTimeInMillis()) {
-                            double vel = trkPnt.getCoor().greatCircleDistance(oldWp.getCoor())
+                            double vel = trkPnt.greatCircleDistance(oldWp)
                                     / (trkPnt.getTime() - oldWp.getTime());
                             velocities.add(vel);
@@ -624,7 +624,6 @@
             }
             for (WayPoint trkPnt : segment) {
-                LatLon c = trkPnt.getCoor();
                 trkPnt.customColoring = segment.getColor();
-                if (Double.isNaN(c.lat()) || Double.isNaN(c.lon())) {
+                if (Double.isNaN(trkPnt.lat()) || Double.isNaN(trkPnt.lon())) {
                     continue;
                 }
@@ -646,5 +645,5 @@
                 }
                 if (oldWp != null) { // other coloring modes need segment for calcuation
-                    double dist = c.greatCircleDistance(oldWp.getCoor());
+                    double dist = trkPnt.greatCircleDistance(oldWp);
                     boolean noDraw = false;
                     switch (colored) {
@@ -658,5 +657,5 @@
                         break;
                     case DIRECTION:
-                        double dirColor = oldWp.getCoor().bearing(trkPnt.getCoor());
+                        double dirColor = oldWp.bearing(trkPnt);
                         color = directionScale.getColor(dirColor);
                         break;
@@ -674,5 +673,5 @@
                     if (!noDraw && (!segment.isUnordered() || !data.fromServer) && (maxLineLength == -1 || dist <= maxLineLength)) {
                         trkPnt.drawLine = true;
-                        double bearing = oldWp.getCoor().bearing(trkPnt.getCoor());
+                        double bearing = oldWp.bearing(trkPnt);
                         trkPnt.dir = ((int) (bearing / Math.PI * 4 + 1.5)) % 8;
                     } else {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/RenderingCLI.java	(revision 18494)
@@ -27,4 +27,5 @@
 import org.openstreetmap.josm.data.ProjectionBounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.coor.conversion.LatLonParser;
@@ -491,5 +492,5 @@
                     EastNorth projAnchorShifted = projAnchor.add(shiftMeter / proj.getMetersPerUnit(),
                             shiftMeter / proj.getMetersPerUnit());
-                    LatLon anchorShifted = proj.eastNorth2latlon(projAnchorShifted);
+                    ILatLon anchorShifted = proj.eastNorth2latlon(projAnchorShifted);
                     return projAnchor.distance(projAnchorShifted) / argAnchor.greatCircleDistance(anchorShifted);
                 };
@@ -559,5 +560,5 @@
             if (argScale != null) {
                 double enPerMeter = pb.getMin().distance(pb.getMax())
-                        / bounds.getMin().greatCircleDistance(bounds.getMax());
+                        / bounds.getMin().greatCircleDistance((ILatLon) bounds.getMax());
                 scale = argScale * enPerMeter / PIXEL_PER_METER;
             } else if (argWidthPx != null) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java	(revision 18494)
@@ -546,5 +546,5 @@
             } else if (ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type || ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL == type) {
 
-                if (e.osm.getDataSet() == null || (e.osm instanceof INode && ((INode) e.osm).getCoor() == null)
+                if (e.osm.getDataSet() == null || (e.osm instanceof INode && !((INode) e.osm).isLatLonKnown())
                         || (!(e.osm instanceof INode) && !isArea(e.osm))) {
                     return ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL == type;
Index: trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/io/GeoJSONWriter.java	(revision 18494)
@@ -33,4 +33,5 @@
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -240,5 +241,5 @@
             final JsonArrayBuilder multiPoint = Json.createArrayBuilder();
             r.getMembers().stream().map(RelationMember::getMember).filter(Node.class::isInstance).map(Node.class::cast)
-                    .map(Node::getCoor).map(latLon -> getCoorArray(null, latLon))
+                    .map(latLon -> getCoorArray(null, latLon))
                     .forEach(multiPoint::add);
             geomObj.add("type", "MultiPoint");
@@ -255,7 +256,7 @@
                     .map(Way::getNodes).map(p -> {
                 JsonArrayBuilder array = getCoorsArray(p);
-                LatLon ll = p.get(0).getCoor();
+                ILatLon ll = p.get(0);
                 // since first node is not duplicated as last node
-                return ll != null ? array.add(getCoorArray(null, ll)) : array;
+                return ll.isLatLonKnown() ? array.add(getCoorArray(null, ll)) : array;
             }).forEach(multiLine::add);
             geomObj.add("type", "MultiLineString");
@@ -297,7 +298,7 @@
                         .map(p -> {
                             JsonArrayBuilder array = getCoorsArray(p);
-                            LatLon ll = p.get(0).getCoor();
+                            ILatLon ll = p.get(0);
                             // since first node is not duplicated as last node
-                            return ll != null ? array.add(getCoorArray(null, ll)) : array;
+                            return ll.isLatLonKnown() ? array.add(getCoorArray(null, ll)) : array;
                         })
                         .forEach(polygon::add);
@@ -311,7 +312,6 @@
             final JsonArrayBuilder builder = Json.createArrayBuilder();
             for (Node n : nodes) {
-                LatLon ll = n.getCoor();
-                if (ll != null) {
-                    builder.add(getCoorArray(null, ll));
+                if (n.isLatLonKnown()) {
+                    builder.add(getCoorArray(null, n));
                 }
             }
@@ -320,5 +320,5 @@
     }
 
-    private JsonArrayBuilder getCoorArray(JsonArrayBuilder builder, LatLon c) {
+    private JsonArrayBuilder getCoorArray(JsonArrayBuilder builder, ILatLon c) {
         return getCoorArray(builder, projection.latlon2eastNorth(c));
     }
Index: trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandler.java	(revision 18494)
@@ -92,5 +92,5 @@
             Point p = mapView.getPoint(ll);
             node = mapView.getNearestNode(p, OsmPrimitive::isUsable);
-            if (node != null && node.getCoor().greatCircleDistance(ll) > Config.getPref().getDouble("remotecontrol.tolerance", 0.1)) {
+            if (node != null && node.greatCircleDistance(ll) > Config.getPref().getDouble("remotecontrol.tolerance", 0.1)) {
                 node = null; // node is too far
             }
Index: trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandler.java	(revision 18494)
@@ -19,4 +19,5 @@
 import org.openstreetmap.josm.command.SequenceCommand;
 import org.openstreetmap.josm.data.UndoRedoHandler;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -129,5 +130,5 @@
             MapView mapView = MainApplication.getMap().mapView;
             nd = mapView.getNearestNode(mapView.getPoint(ll), OsmPrimitive::isUsable);
-            if (nd != null && nd.getCoor().greatCircleDistance(ll) > Config.getPref().getDouble("remote.tolerance", 0.1)) {
+            if (nd != null && nd.greatCircleDistance(ll) > Config.getPref().getDouble("remote.tolerance", 0.1)) {
                 nd = null; // node is too far
             }
@@ -136,5 +137,5 @@
         Node prev = null;
         for (Entry<LatLon, Node> entry : addedNodes.entrySet()) {
-            LatLon lOld = entry.getKey();
+            ILatLon lOld = entry.getKey();
             if (lOld.greatCircleDistance(ll) < Config.getPref().getDouble("remotecontrol.tolerance", 0.1)) {
                 prev = entry.getValue();
Index: trunk/src/org/openstreetmap/josm/io/session/SessionReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/io/session/SessionReader.java	(revision 18494)
@@ -37,4 +37,5 @@
 import org.openstreetmap.josm.data.ViewportData;
 import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.ILatLon;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -144,6 +145,6 @@
             // not too small to avoid rounding errors.
             double dist = 0.01 * proj.getDefaultZoomInPPD();
-            LatLon ll1 = proj.eastNorth2latlon(new EastNorth(centerEN.east() - dist, centerEN.north()));
-            LatLon ll2 = proj.eastNorth2latlon(new EastNorth(centerEN.east() + dist, centerEN.north()));
+            ILatLon ll1 = proj.eastNorth2latlon(new EastNorth(centerEN.east() - dist, centerEN.north()));
+            ILatLon ll2 = proj.eastNorth2latlon(new EastNorth(centerEN.east() + dist, centerEN.north()));
             double meterPerEasting = ll1.greatCircleDistance(ll2) / dist / 2;
             double scale = meterPerPixel / meterPerEasting; // unit: easting per pixel
Index: trunk/src/org/openstreetmap/josm/tools/Geometry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 18493)
+++ trunk/src/org/openstreetmap/josm/tools/Geometry.java	(revision 18494)
@@ -1401,6 +1401,6 @@
         if (one == null || two == null || one.isIncomplete()
                 || two.isIncomplete()) return Double.NaN;
-        if (one instanceof Node && two instanceof Node) {
-            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
+        if (one instanceof ILatLon && two instanceof ILatLon) {
+            rValue = ((ILatLon) one).greatCircleDistance(((ILatLon) two));
         } else if (one instanceof Node && two instanceof Way) {
             rValue = getDistanceWayNode((Way) two, (Node) one);
