Ticket #17616: 17616_v8.patch

File 17616_v8.patch, 26.7 KB (added by taylor.smock, 6 years ago)

Return Double.NaN when a primitive is incomplete and modify docs to specify that the OsmPrimitives should be fully downloaded for accuracy.

  • src/org/openstreetmap/josm/data/gpx/GpxDistance.java

     
    3131     */
    3232    public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) {
    3333        return gpxData.getTrackPoints()
    34                 .mapToDouble(tp -> getDistance(p, tp))
     34                .mapToDouble(tp -> Geometry.getDistance(p, new Node(tp.getCoor())))
    3535                .filter(x -> x >= 0)
    3636                .min().orElse(Double.MAX_VALUE);
    3737    }
     
    4141     * @param p OsmPrimitive to get the distance to the WayPoint
    4242     * @param waypoint WayPoint to get the distance from
    4343     * @return The shortest distance between p and waypoint
     44     * @deprecated Use {@code Geometry.getDistance(p, new Node(waypoint.getCoor()))}
     45     * instead
    4446     */
     47    @Deprecated
    4548    public static double getDistance(OsmPrimitive p, WayPoint waypoint) {
    46         if (p instanceof Node) {
    47             return getDistanceNode((Node) p, waypoint);
    48         } else if (p instanceof Way) {
    49             return getDistanceWay((Way) p, waypoint);
    50         } else if (p instanceof Relation) {
    51             return getDistanceRelation((Relation) p, waypoint);
    52         }
    53         return Double.MAX_VALUE;
     49        return Geometry.getDistance(p, new Node(waypoint.getCoor()));
    5450    }
    5551
    5652    /**
     
    5854     * @param relation Relation to get the distance from
    5955     * @param waypoint WayPoint to get the distance to
    6056     * @return The distance between the relation and the waypoint
     57     * @deprecated Use {@code Geometry.getDistance(relation, new Node(waypoint.getCoor()))}
     58     * instead
    6159     */
     60    @Deprecated
    6261    public static double getDistanceRelation(Relation relation, WayPoint waypoint) {
    6362        double shortestDistance = Double.MAX_VALUE;
    6463        List<Node> nodes = new ArrayList<>(relation.getMemberPrimitives(Node.class));
     
    8584     * @param way Way to get the distance from
    8685     * @param waypoint WayPoint to get the distance to
    8786     * @return The distance between the way and the waypoint
     87     * @deprecated Use {@code Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor()))} instead
    8888     */
     89    @Deprecated
    8990    public static double getDistanceWay(Way way, WayPoint waypoint) {
    90         double shortestDistance = Double.MAX_VALUE;
    91         if (way == null || waypoint == null) return shortestDistance;
    92         LatLon llwaypoint = waypoint.getCoor();
    93         EastNorth enwaypoint = new EastNorth(llwaypoint.getY(), llwaypoint.getX());
    94         for (int i = 0; i < way.getNodesCount() - 1; i++) {
    95             double distance = Double.MAX_VALUE;
    96             LatLon llfirst = way.getNode(i).getCoor();
    97             LatLon llsecond = way.getNode(i + 1).getCoor();
    98             EastNorth first = new EastNorth(llfirst.getY(), llfirst.getX());
    99             EastNorth second = new EastNorth(llsecond.getY(), llsecond.getX());
    100             if (first.isValid() && second.isValid()) {
    101                 EastNorth closestPoint = Geometry.closestPointToSegment(first, second, enwaypoint);
    102                 distance = llwaypoint.greatCircleDistance(new LatLon(closestPoint.getX(), closestPoint.getY()));
    103             } else if (first.isValid() && !second.isValid()) {
    104                 distance = getDistanceEastNorth(first, waypoint);
    105             } else if (!first.isValid() && second.isValid()) {
    106                 distance = getDistanceEastNorth(second, waypoint);
    107             } else if (!first.isValid() && !second.isValid()) {
    108                 distance = Double.MAX_VALUE;
    109             }
    110             if (distance < shortestDistance) shortestDistance = distance;
    111 
    112         }
    113         return shortestDistance;
     91        if (way == null || waypoint == null) return Double.MAX_VALUE;
     92        return Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor()));
    11493    }
    11594
    11695    /**
     
    11897     * @param node Node to get the distance from
    11998     * @param waypoint WayPoint to get the distance to
    12099     * @return The distance between the two points
     100     * @deprecated Use {@code Geometry.getDistance(node, new Node(waypoint.getCoor()))}
     101     * instead
    121102     */
     103    @Deprecated
    122104    public static double getDistanceNode(Node node, WayPoint waypoint) {
    123         if (node == null) return Double.MAX_VALUE;
    124         return getDistanceLatLon(node.getCoor(), waypoint);
     105        if (node == null || waypoint == null) return Double.MAX_VALUE;
     106        return Geometry.getDistance(node, new Node(waypoint.getCoor()));
    125107    }
    126108
    127109    /**
     
    129111     * @param en The EastNorth to get the distance to
    130112     * @param waypoint WayPoint to get the distance to
    131113     * @return The distance between the two points
     114     * @deprecated Use {@code Geometry.getDistance(new Node(en), new Node(waypoint.getCoor()))} instead
    132115     */
     116    @Deprecated
    133117    public static double getDistanceEastNorth(EastNorth en, WayPoint waypoint) {
    134         if (en == null || !en.isValid()) return Double.MAX_VALUE;
    135         return getDistanceLatLon(new LatLon(en.getY(), en.getX()), waypoint);
     118        if (en == null || waypoint == null) return Double.MAX_VALUE;
     119        return Geometry.getDistance(new Node(en), new Node(waypoint.getCoor()));
    136120    }
    137121
    138122    /**
     
    140124     * @param latlon LatLon to get the distance from
    141125     * @param waypoint WayPoint to get the distance to
    142126     * @return The distance between the two points
     127     * @deprecated Use {@code Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor()))} instead
    143128     */
     129    @Deprecated
    144130    public static double getDistanceLatLon(LatLon latlon, WayPoint waypoint) {
    145131        if (latlon == null || waypoint == null || waypoint.getCoor() == null) return Double.MAX_VALUE;
    146         return waypoint.getCoor().greatCircleDistance(latlon);
     132        return Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor()));
    147133    }
    148134}
  • src/org/openstreetmap/josm/tools/Geometry.java

     
    88import java.math.BigDecimal;
    99import java.math.MathContext;
    1010import java.util.ArrayList;
     11import java.util.Collection;
    1112import java.util.Collections;
    1213import java.util.Comparator;
    1314import java.util.EnumSet;
     
    1415import java.util.LinkedHashSet;
    1516import java.util.List;
    1617import java.util.Set;
     18import java.util.TreeSet;
    1719import java.util.function.Predicate;
    1820import java.util.stream.Collectors;
    1921
     
    3032import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
    3133import org.openstreetmap.josm.data.osm.Node;
    3234import org.openstreetmap.josm.data.osm.NodePositionComparator;
     35import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3336import org.openstreetmap.josm.data.osm.Relation;
    3437import org.openstreetmap.josm.data.osm.Way;
     38import org.openstreetmap.josm.data.osm.WaySegment;
    3539import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    3640import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
    3741import org.openstreetmap.josm.data.projection.Projection;
     
    10701074        }
    10711075        return new AreaAndPerimeter(Math.abs(area) / 2, perimeter);
    10721076    }
     1077
     1078    /**
     1079     * Get the closest primitive to {@code osm} from the collection of
     1080     * OsmPrimitive {@code primitives}
     1081     *
     1082     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1083     *
     1084     * @param <T> The return type of the primitive
     1085     * @param osm The primitive to get the distances from
     1086     * @param primitives The collection of primitives to get the distance to
     1087     * @return The closest {@link OsmPrimitive}. This is not determinative.
     1088     * To get all primitives that share the same distance, use
     1089     * {@link Geometry#getClosestPrimitives}.
     1090     * @since xxx
     1091     */
     1092    public static <T extends OsmPrimitive> T getClosestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1093        Collection<T> collection = getClosestPrimitives(osm, primitives);
     1094        return collection.iterator().next();
     1095    }
     1096
     1097    /**
     1098     * Get the closest primitives to {@code osm} from the collection of
     1099     * OsmPrimitive {@code primitives}
     1100     *
     1101     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1102     *
     1103     * @param <T> The return type of the primitive
     1104     * @param osm The primitive to get the distances from
     1105     * @param primitives The collection of primitives to get the distance to
     1106     * @return The closest {@link OsmPrimitive}s. May be empty.
     1107     * @since xxx
     1108     */
     1109    public static <T extends OsmPrimitive> Collection<T> getClosestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1110        double lowestDistance = Double.MAX_VALUE;
     1111        TreeSet<T> closest = new TreeSet<>();
     1112        for (T primitive : primitives) {
     1113            double distance = getDistance(osm, primitive);
     1114            if (Double.isNaN(distance)) continue;
     1115            if (distance < lowestDistance) {
     1116                closest.clear();
     1117                lowestDistance = distance;
     1118                closest.add(primitive);
     1119            } else if (distance == lowestDistance) {
     1120                closest.add(primitive);
     1121            }
     1122        }
     1123        return closest;
     1124    }
     1125
     1126    /**
     1127     * Get the furthest primitive to {@code osm} from the collection of
     1128     * OsmPrimitive {@code primitives}
     1129     *
     1130     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1131     *
     1132     * It does NOT give the furthest primitive based off of the furthest
     1133     * part of that primitive
     1134     * @param <T> The return type of the primitive
     1135     * @param osm The primitive to get the distances from
     1136     * @param primitives The collection of primitives to get the distance to
     1137     * @return The furthest {@link OsmPrimitive}.  This is not determinative.
     1138     * To get all primitives that share the same distance, use
     1139     * {@link Geometry#getFurthestPrimitives}
     1140     * @since xxx
     1141     */
     1142    public static <T extends OsmPrimitive> T getFurthestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1143        return getFurthestPrimitives(osm, primitives).iterator().next();
     1144    }
     1145
     1146    /**
     1147     * Get the furthest primitives to {@code osm} from the collection of
     1148     * OsmPrimitive {@code primitives}
     1149     *
     1150     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1151     *
     1152     * It does NOT give the furthest primitive based off of the furthest
     1153     * part of that primitive
     1154     * @param <T> The return type of the primitive
     1155     * @param osm The primitive to get the distances from
     1156     * @param primitives The collection of primitives to get the distance to
     1157     * @return The furthest {@link OsmPrimitive}s. It may return an empty collection.
     1158     * @since xxx
     1159     */
     1160    public static <T extends OsmPrimitive> Collection<T> getFurthestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1161        double furthestDistance = Double.NEGATIVE_INFINITY;
     1162        TreeSet<T> furthest = new TreeSet<>();
     1163        for (T primitive : primitives) {
     1164            double distance = getDistance(osm, primitive);
     1165            if (Double.isNaN(distance)) continue;
     1166            if (distance > furthestDistance) {
     1167                furthest.clear();
     1168                furthestDistance = distance;
     1169                furthest.add(primitive);
     1170            } else if (distance == furthestDistance) {
     1171                furthest.add(primitive);
     1172            }
     1173        }
     1174        return furthest;
     1175    }
     1176
     1177    /**
     1178     * Get the distance between different {@link OsmPrimitive}s
     1179     * @param one The primitive to get the distance from
     1180     * @param two The primitive to get the distance to
     1181     * @return The distance between the primitives in meters
     1182     * (or the unit of the current projection, see {@link Projection}).
     1183     * May return {@link Double#NaN} if one of the primitives is incomplete.
     1184     * @since xxx
     1185     */
     1186    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1187        double rValue = Double.MAX_VALUE;
     1188        if (one == null || two == null || one.isIncomplete()
     1189                || two.isIncomplete()) return Double.NaN;
     1190        if (one instanceof Node && two instanceof Node) {
     1191            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1192        } else if (one instanceof Node && two instanceof Way) {
     1193            rValue = getDistanceWayNode((Way) two, (Node) one);
     1194        } else if (one instanceof Way && two instanceof Node) {
     1195            rValue = getDistanceWayNode((Way) one, (Node) two);
     1196        } else if (one instanceof Way && two instanceof Way) {
     1197            rValue = getDistanceWayWay((Way) one, (Way) two);
     1198        } else if (one instanceof Relation && !(two instanceof Relation)) {
     1199            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1200                double currentDistance = getDistance(osmPrimitive, two);
     1201                if (currentDistance < rValue) rValue = currentDistance;
     1202            }
     1203        } else if (!(one instanceof Relation) && two instanceof Relation) {
     1204            for (OsmPrimitive osmPrimitive : ((Relation) two).getMemberPrimitives()) {
     1205                double currentDistance = getDistance(osmPrimitive, one);
     1206                if (currentDistance < rValue) rValue = currentDistance;
     1207            }
     1208        } else if (one instanceof Relation && two instanceof Relation) {
     1209            for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) {
     1210                for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) {
     1211                    double currentDistance = getDistance(osmPrimitive1, osmPrimitive2);
     1212                    if (currentDistance < rValue) rValue = currentDistance;
     1213                }
     1214            }
     1215        }
     1216        return rValue;
     1217    }
     1218
     1219    /**
     1220     * Get the distance between a way and a node
     1221     * @param way The way to get the distance from
     1222     * @param node The node to get the distance to
     1223     * @return The distance between the {@code way} and the {@code node} in
     1224     * meters (or the unit of the current projection, see {@link Projection}).
     1225     * May return {@link Double#NaN} if the primitives are incomplete.
     1226     * @since xxx
     1227     */
     1228    public static double getDistanceWayNode(Way way, Node node) {
     1229        if (way == null || node == null || way.isIncomplete()
     1230                || node.isIncomplete()) return Double.NaN;
     1231        double rValue = Double.MAX_VALUE;
     1232        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1233            EastNorth point = Geometry.closestPointToSegment(
     1234                    nodes.a.getEastNorth(), nodes.b.getEastNorth(),
     1235                    node.getEastNorth());
     1236            double distance = point.distance(node.getEastNorth());
     1237            if (distance < rValue) rValue = distance;
     1238        }
     1239        return rValue;
     1240    }
     1241
     1242    /**
     1243     * Get the closest {@link WaySegment} from a way to a primitive.
     1244     * @param way The {@link Way} to get the distance from and the {@link WaySegment}
     1245     * @param primitive The {@link OsmPrimitive} to get the distance to
     1246     * @return The {@link WaySegment} that is closest to {@code primitive} from {@code way}.
     1247     * If there are multiple {@link WaySegment}s with the same distance, the last
     1248     * {@link WaySegment} with the same distance will be returned.
     1249     * May return {@code null} if the way has fewer than two nodes or one
     1250     * of the primitives is incomplete.
     1251     * @since xxx
     1252     */
     1253    public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) {
     1254        if (way == null || primitive == null || way.isIncomplete()
     1255                || primitive.isIncomplete()) return null;
     1256        double lowestDistance = Double.MAX_VALUE;
     1257        Pair<Node, Node> closestNodes = null;
     1258        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1259            Way tWay = new Way();
     1260            tWay.addNode(nodes.a);
     1261            tWay.addNode(nodes.b);
     1262            double distance = getDistance(tWay, primitive);
     1263            if (distance < lowestDistance) {
     1264                lowestDistance = distance;
     1265                closestNodes = nodes;
     1266            }
     1267        }
     1268        if (closestNodes == null) return null;
     1269        return WaySegment.forNodePair(way, closestNodes.a, closestNodes.b);
     1270    }
     1271
     1272    /**
     1273     * Get the distance between different ways
     1274     * @param one The way to get the distance from
     1275     * @param two The {@link Way} to get the distance to
     1276     * @return The shortest distance between the ways in meters
     1277     * (or the unit of the current projection, see {@link Projection}).
     1278     * May return {@link Double#NaN}.
     1279     * @since xxx
     1280     */
     1281    public static double getDistanceWayWay(Way one, Way two) {
     1282        if (one == null || two == null || one.isIncomplete()
     1283                || two.isIncomplete()) return Double.NaN;
     1284
     1285        double rValue = Double.MAX_VALUE;
     1286        for (Pair<Node, Node> oneNodes : one.getNodePairs(false)) {
     1287            for (Pair<Node, Node> twoNodes : two.getNodePairs(false)) {
     1288                double distance = getDistanceSegmentSegment(oneNodes.a, oneNodes.b, twoNodes.a, twoNodes.b);
     1289                if (distance < rValue) rValue = distance;
     1290            }
     1291        }
     1292        return rValue;
     1293    }
     1294
     1295    /**
     1296     * Get the distance between different {@link WaySegment}s
     1297     * @param one A {@link WaySegment} to get the distance from
     1298     * @param two A {@link WaySegment} to get the distance to
     1299     * @return The distance between the two {@link WaySegment}s in meters
     1300     * (or the unit of the current projection, see {@link Projection}).
     1301     * May return {@link Double#NaN}.
     1302     * @since xxx
     1303     */
     1304    public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) {
     1305        return getDistanceSegmentSegment(one.getFirstNode(), one.getSecondNode(), two.getFirstNode(), two.getSecondNode());
     1306    }
     1307
     1308    /**
     1309     * Get the distance between different {@link WaySegment}s
     1310     * @param way1Node1 The first node of the first WaySegment
     1311     * @param way1Node2 The second node of the second WaySegment
     1312     * @param way2Node1 The first node of the second WaySegment
     1313     * @param way2Node2 The second node of the second WaySegment
     1314     * @return The distance between the two {@link WaySegment}s in meters
     1315     * (or the unit of the current projection, see {@link Projection}).
     1316     * May return {@link Double#NaN}.
     1317     * @since xxx
     1318     */
     1319    public static double getDistanceSegmentSegment(Node way1Node1, Node way1Node2, Node way2Node1, Node way2Node2) {
     1320        if (way1Node1.isIncomplete() || way1Node2.isIncomplete()
     1321                || way2Node1.isIncomplete() || way2Node2.isIncomplete())
     1322            return Double.NaN;
     1323        EastNorth vectorOne = way1Node2.getEastNorth().subtract(way1Node1.getEastNorth());
     1324        EastNorth vectorTwo = way2Node2.getEastNorth().subtract(way2Node1.getEastNorth());
     1325        EastNorth vectorThree = way1Node1.getEastNorth().subtract(way2Node1.getEastNorth());
     1326        double smallNumber = 0.00000000001;
     1327        double a = dot(vectorOne, vectorOne);
     1328        double b = dot(vectorOne, vectorTwo);
     1329        double c = dot(vectorTwo, vectorTwo);
     1330        double d = dot(vectorOne, vectorThree);
     1331        double e = dot(vectorTwo, vectorThree);
     1332
     1333        double dotCombination = a * c - b * b;
     1334        double sc;
     1335        double sN;
     1336        double sD = d;
     1337        double tc;
     1338        double tN;
     1339        double tD = dotCombination;
     1340        if (dotCombination < smallNumber) {
     1341            sN = 0.0;
     1342            sD = 1.0;
     1343            tN = e;
     1344            tD = c;
     1345        } else {
     1346            sN = (b * e - c * d);
     1347            tN = (a * e - b * d);
     1348            if (sN < 0.0) {
     1349                sN = 0.0;
     1350                tN = e;
     1351                tD = c;
     1352            } else if (sN > sD) {
     1353                sN = sD;
     1354                tN = e + b;
     1355                tD = c;
     1356            }
     1357        }
     1358
     1359        if (tN < 0.0) {
     1360            tN = 0.0;
     1361            if (-d < 0.0) sN = 0.0;
     1362            else if (-d > a) sN = sD;
     1363            else {
     1364                sN = -d;
     1365                sD = a;
     1366            }
     1367        } else if (tN > tD) {
     1368            tN = tD;
     1369            if ((-d + b) < 0.0) sN = 0;
     1370            else if ((-d + b) > a) sN = sD;
     1371            else {
     1372                sN = (-d + b);
     1373                sD = a;
     1374            }
     1375        }
     1376        sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD;
     1377        tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD;
     1378        EastNorth p1 = way1Node1.getEastNorth().interpolate(way1Node2.getEastNorth(), sc);
     1379        EastNorth p2 = way2Node1.getEastNorth().interpolate(way2Node2.getEastNorth(), tc);
     1380        return p1.distance(p2);
     1381    }
     1382
     1383    /**
     1384     * Get the dot product of two different EastNorth points
     1385     * @param one The originating EastNorth
     1386     * @param two The final EastNorth
     1387     * @return the dot product of the EastNorths
     1388     * @since xxx
     1389     */
     1390    public static double dot(EastNorth one, EastNorth two) {
     1391        return two.getX() * one.getX() + one.getY() * two.getY();
     1392    }
    10731393}
  • test/unit/org/openstreetmap/josm/tools/GeometryTest.java

     
    44import static org.junit.Assert.assertEquals;
    55
    66import java.io.FileInputStream;
     7import java.util.ArrayList;
    78import java.util.Arrays;
    89import java.util.List;
    910
     
    1516import org.openstreetmap.josm.data.coor.LatLon;
    1617import org.openstreetmap.josm.data.osm.DataSet;
    1718import org.openstreetmap.josm.data.osm.Node;
     19import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1820import org.openstreetmap.josm.data.osm.Relation;
     21import org.openstreetmap.josm.data.osm.RelationMember;
    1922import org.openstreetmap.josm.data.osm.Way;
    2023import org.openstreetmap.josm.data.osm.search.SearchCompiler;
    2124import org.openstreetmap.josm.io.OsmReader;
     
    158161        assertEquals(new EastNorth(125, 300), Geometry.getCentroidEN(Arrays.asList(en1, en2)));
    159162        assertEquals(new EastNorth(150, 266d + 2d/3d), Geometry.getCentroidEN(Arrays.asList(en1, en2, en3)));
    160163    }
     164
     165    /**
     166     * Test of {@link Geometry#getDistance} method.
     167     */
     168    @Test
     169    public void testGetDistance() {
     170        Node node1 = new Node(new LatLon(0, 0));
     171        Node node2 = new Node(new LatLon(0.1, 1));
     172        Node node3 = new Node(new LatLon(1.1, 0.1));
     173        Node node4 = new Node(new LatLon(1, 1.1));
     174        Way way1 = TestUtils.newWay("", node1, node2);
     175        Way way2 = TestUtils.newWay("", node3, node4);
     176        Relation testRelation1 = new Relation();
     177        Relation testRelation2 = new Relation();
     178        testRelation1.addMember(new RelationMember("", way1));
     179        testRelation1.addMember(new RelationMember("", way2));
     180        testRelation2.addMember(new RelationMember("", node1));
     181        testRelation2.addMember(new RelationMember("", node2));
     182        testRelation2.addMember(new RelationMember("", node3));
     183        testRelation2.addMember(new RelationMember("", node4));
     184
     185        double distance = Geometry.getDistance(null, node3);
     186        assertEquals(Double.NaN, distance, 0.1);
     187
     188        distance = Geometry.getDistance(way1, null);
     189        assertEquals(Double.NaN, distance, 0.1);
     190
     191        distance = Geometry.getDistance(null, null);
     192        assertEquals(Double.NaN, distance, 0.1);
     193
     194        distance = Geometry.getDistance(node1, node2);
     195        assertEquals(111874.6474307704, distance, 0.1);
     196
     197        distance = Geometry.getDistance(way1, node3);
     198        assertEquals(120743.55085962385, distance, 0.1);
     199
     200        distance = Geometry.getDistance(node3, way1);
     201        assertEquals(120743.55085962385, distance, 0.1);
     202
     203        distance = Geometry.getDistance(way1, way2);
     204        assertEquals(100803.63714283936, distance, 0.1);
     205
     206        distance = Geometry.getDistance(testRelation1, new Node(new LatLon(0, 0.5)));
     207        assertEquals(5538.354450686605, distance, 0.1);
     208
     209        distance = Geometry.getDistance(new Node(new LatLon(0, 0.5)), testRelation1);
     210        assertEquals(5538.354450686605, distance, 0.1);
     211
     212        distance = Geometry.getDistance(testRelation1, testRelation2);
     213        assertEquals(0.0, distance, 0.1);
     214    }
     215
     216    /**
     217     * Test of {@link Geometry#getClosestPrimitive} method
     218     */
     219    @Test
     220    public void testGetClosestPrimitive() {
     221        Node node1 = new Node(new LatLon(0, 0));
     222        Node node2 = new Node(new LatLon(0.1, 1));
     223        Node node3 = new Node(new LatLon(1.1, 0.1));
     224        Node node4 = new Node(new LatLon(1, 1.1));
     225        Way way1 = TestUtils.newWay("", node1, node2);
     226        Way way2 = TestUtils.newWay("", node3, node4);
     227
     228        List<OsmPrimitive> primitives = new ArrayList<>();
     229        primitives.add(way1);
     230        primitives.add(way2);
     231        OsmPrimitive closest = Geometry.getClosestPrimitive(node1, primitives);
     232        assertEquals(way1, closest);
     233    }
     234
     235    /**
     236     * Test of {@link Geometry#getFurthestPrimitive} method
     237     */
     238    @Test
     239    public void testGetFurthestPrimitive() {
     240        Node node1 = new Node(new LatLon(0, 0));
     241        Node node2 = new Node(new LatLon(0, 1.1));
     242        Node node3 = new Node(new LatLon(1, 0.1));
     243        Node node4 = new Node(new LatLon(1.1, 1));
     244        Way way1 = TestUtils.newWay("", node1, node2);
     245        Way way2 = TestUtils.newWay("", node3, node4);
     246        Way way3 = TestUtils.newWay("", node2, node4);
     247        Way way4 = TestUtils.newWay("", node1, node3);
     248
     249        List<OsmPrimitive> primitives = new ArrayList<>();
     250        primitives.add(way1);
     251        OsmPrimitive furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(0, 0.75)), primitives);
     252        assertEquals(way1, furthest);
     253        primitives.add(way2);
     254        primitives.add(way3);
     255        primitives.add(way4);
     256        furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(0, 0.5)), primitives);
     257        assertEquals(way2, furthest);
     258        furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(.25, 0.5)), primitives);
     259        assertEquals(way2, furthest);
     260    }
     261
     262    /**
     263     * Test of {@link Geometry#getClosestWaySegment} method
     264     */
     265    @Test
     266    public void testGetClosestWaySegment() {
     267        Node node1 = new Node(new LatLon(0, 0));
     268        Node node2 = new Node(new LatLon(0, 1));
     269        Node node3 = new Node(new LatLon(0.3, 0.5));
     270        Node node4 = new Node(new LatLon(0.1, 0));
     271        Way way1 = TestUtils.newWay("", node1, node2, node3, node4);
     272
     273        Way closestSegment = Geometry.getClosestWaySegment(way1, new Node(new LatLon(0, 0.5))).toWay();
     274        Assert.assertTrue(closestSegment.containsNode(node1));
     275        Assert.assertTrue(closestSegment.containsNode(node2));
     276    }
    161277}