Ticket #17616: 17616_v7.patch

File 17616_v7.patch, 25.5 KB (added by taylor.smock, 6 years ago)

Use Pair<Node, Node> instead of WaySegments for some calculations, add units (and why it is those units) to the javadocs, modify tests to not be horizontal so bounding boxes aren't exactly the line (the methods don't use bounding boxes, but may be refactored in the future), document that the get(CLOSTEST/FURTHEST)Primitive may return a different result each time (it shouldn't, since the underlying collection is currently a TreeSet, but that may end up being changed in the future).

  • 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     * @param <T> The return type of the primitive
     1082     * @param osm The primitive to get the distances from
     1083     * @param primitives The collection of primitives to get the distance to
     1084     * @return The closest {@link OsmPrimitive}. This is not determinative.
     1085     * To get all primitives that share the same distance, use
     1086     * {@link Geometry#getClosestPrimitives}.
     1087     * @since xxx
     1088     */
     1089    public static <T extends OsmPrimitive> T getClosestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1090        Collection<T> collection = getClosestPrimitives(osm, primitives);
     1091        return collection.iterator().next();
     1092    }
     1093
     1094    /**
     1095     * Get the closest primitives to {@code osm} from the collection of
     1096     * OsmPrimitive {@code primitives}
     1097     * @param <T> The return type of the primitive
     1098     * @param osm The primitive to get the distances from
     1099     * @param primitives The collection of primitives to get the distance to
     1100     * @return The closest {@link OsmPrimitive}s.
     1101     * @since xxx
     1102     */
     1103    public static <T extends OsmPrimitive> Collection<T> getClosestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1104        double lowestDistance = Double.MAX_VALUE;
     1105        TreeSet<T> closest = new TreeSet<>();
     1106        for (T primitive : primitives) {
     1107            double distance = getDistance(osm, primitive);
     1108            if (distance < lowestDistance) {
     1109                closest.clear();
     1110                lowestDistance = distance;
     1111                closest.add(primitive);
     1112            } else if (distance == lowestDistance) {
     1113                closest.add(primitive);
     1114            }
     1115        }
     1116        return closest;
     1117    }
     1118
     1119    /**
     1120     * Get the furthest primitive to {@code osm} from the collection of
     1121     * OsmPrimitive {@code primitives}
     1122     *
     1123     * This measures distance to the closest part of the OsmPrimitives
     1124     * (it does NOT give the furthest primitive based off of the furthest
     1125     * part of that primitive)
     1126     * @param <T> The return type of the primitive
     1127     * @param osm The primitive to get the distances from
     1128     * @param primitives The collection of primitives to get the distance to
     1129     * @return The furthest {@link OsmPrimitive}.  This is not determinative.
     1130     * To get all primitives that share the same distance, use
     1131     * {@link Geometry#getFurthestPrimitives}
     1132     * @since xxx
     1133     */
     1134    public static <T extends OsmPrimitive> T getFurthestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1135        return getFurthestPrimitives(osm, primitives).iterator().next();
     1136    }
     1137
     1138    /**
     1139     * Get the furthest primitives to {@code osm} from the collection of
     1140     * OsmPrimitive {@code primitives}
     1141     *
     1142     * This measures distance to the closest part of the OsmPrimitives
     1143     * (it does NOT give the furthest primitive based off of the furthest
     1144     * part of that primitive)
     1145     * @param <T> The return type of the primitive
     1146     * @param osm The primitive to get the distances from
     1147     * @param primitives The collection of primitives to get the distance to
     1148     * @return The furthest {@link OsmPrimitive}s.
     1149     * @since xxx
     1150     */
     1151    public static <T extends OsmPrimitive> Collection<T> getFurthestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1152        double furthestDistance = Double.NEGATIVE_INFINITY;
     1153        TreeSet<T> furthest = new TreeSet<>();
     1154        for (T primitive : primitives) {
     1155            double distance = getDistance(osm, primitive);
     1156            if (distance > furthestDistance) {
     1157                furthest.clear();
     1158                furthestDistance = distance;
     1159                furthest.add(primitive);
     1160            } else if (distance == furthestDistance) {
     1161                furthest.add(primitive);
     1162            }
     1163        }
     1164        return furthest;
     1165    }
     1166
     1167    /**
     1168     * Get the distance between different {@link OsmPrimitive}s
     1169     * @param one The primitive to get the distance from
     1170     * @param two The primitive to get the distance to
     1171     * @return The distance between the primitives in meters
     1172     * (or the unit of the current projection, see {@link Projection}).
     1173     * @since xxx
     1174     */
     1175    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1176        double rValue = Double.MAX_VALUE;
     1177        if (one == null || two == null) return rValue;
     1178        if (one instanceof Node && two instanceof Node) {
     1179            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1180        } else if (one instanceof Node && two instanceof Way) {
     1181            rValue = getDistanceWayNode((Way) two, (Node) one);
     1182        } else if (one instanceof Way && two instanceof Node) {
     1183            rValue = getDistanceWayNode((Way) one, (Node) two);
     1184        } else if (one instanceof Way && two instanceof Way) {
     1185            rValue = getDistanceWayWay((Way) one, (Way) two);
     1186        } else if (one instanceof Relation && !(two instanceof Relation)) {
     1187            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1188                double currentDistance = getDistance(osmPrimitive, two);
     1189                if (currentDistance < rValue) rValue = currentDistance;
     1190            }
     1191        } else if (!(one instanceof Relation) && two instanceof Relation) {
     1192            for (OsmPrimitive osmPrimitive : ((Relation) two).getMemberPrimitives()) {
     1193                double currentDistance = getDistance(osmPrimitive, one);
     1194                if (currentDistance < rValue) rValue = currentDistance;
     1195            }
     1196        } else if (one instanceof Relation && two instanceof Relation) {
     1197            for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) {
     1198                for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) {
     1199                    double currentDistance = getDistance(osmPrimitive1, osmPrimitive2);
     1200                    if (currentDistance < rValue) rValue = currentDistance;
     1201                }
     1202            }
     1203        }
     1204        return rValue;
     1205    }
     1206
     1207    /**
     1208     * Get the distance between a way and a node
     1209     * @param way The way to get the distance from
     1210     * @param node The node to get the distance to
     1211     * @return The distance between the {@code way} and the {@code node} in meters
     1212     * (or the unit of the current projection, see {@link Projection}).
     1213     * @since xxx
     1214     */
     1215    public static double getDistanceWayNode(Way way, Node node) {
     1216        double rValue = Double.MAX_VALUE;
     1217        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1218            EastNorth point = Geometry.closestPointToSegment(nodes.a.getEastNorth(), nodes.b.getEastNorth(), node.getEastNorth());
     1219            double distance = point.distance(node.getEastNorth());
     1220            if (distance < rValue) rValue = distance;
     1221        }
     1222        return rValue;
     1223    }
     1224
     1225    /**
     1226     * Get the closest {@link WaySegment} from a way to a primitive.
     1227     * @param way The {@link Way} to get the distance from and the {@link WaySegment}
     1228     * @param primitive The {@link OsmPrimitive} to get the distance to
     1229     * @return The {@link WaySegment} that is closest to {@code primitive} from {@code way}.
     1230     * If there are multiple {@link WaySegment}s with the same distance, the last
     1231     * {@link WaySegment} with the same distance will be returned.
     1232     * May return {@code null} if the way has fewer than two nodes.
     1233     * @since xxx
     1234     */
     1235    public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) {
     1236        double lowestDistance = Double.MAX_VALUE;
     1237        Pair<Node, Node> closestNodes = null;
     1238        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1239            Way tWay = new Way();
     1240            tWay.addNode(nodes.a);
     1241            tWay.addNode(nodes.b);
     1242            double distance = getDistance(tWay, primitive);
     1243            if (distance < lowestDistance) {
     1244                lowestDistance = distance;
     1245                closestNodes = nodes;
     1246            }
     1247        }
     1248        if (closestNodes == null) return null;
     1249        return WaySegment.forNodePair(way, closestNodes.a, closestNodes.b);
     1250    }
     1251
     1252    /**
     1253     * Get the distance between different ways
     1254     * @param one The way to get the distance from
     1255     * @param two The {@link Way} to get the distance to
     1256     * @return The shortest distance between the ways in meters
     1257     * (or the unit of the current projection, see {@link Projection}).
     1258     * @since xxx
     1259     */
     1260    public static double getDistanceWayWay(Way one, Way two) {
     1261        double rValue = Double.MAX_VALUE;
     1262        for (Pair<Node, Node> oneNodes : one.getNodePairs(false)) {
     1263            for (Pair<Node, Node> twoNodes : two.getNodePairs(false)) {
     1264                double distance = getDistanceSegmentSegment(oneNodes.a, oneNodes.b, twoNodes.a, twoNodes.b);
     1265                if (distance < rValue) rValue = distance;
     1266            }
     1267        }
     1268        return rValue;
     1269    }
     1270
     1271    /**
     1272     * Get the distance between different {@link WaySegment}s
     1273     * @param one A {@link WaySegment} to get the distance from
     1274     * @param two A {@link WaySegment} to get the distance to
     1275     * @return The distance between the two {@link WaySegment}s in meters
     1276     * (or the unit of the current projection, see {@link Projection}).
     1277     * @since xxx
     1278     */
     1279    public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) {
     1280        return getDistanceSegmentSegment(one.getFirstNode(), one.getSecondNode(), two.getFirstNode(), two.getSecondNode());
     1281    }
     1282
     1283    /**
     1284     * Get the distance between different {@link WaySegment}s
     1285     * @param way1Node1 The first node of the first WaySegment
     1286     * @param way1Node2 The second node of the second WaySegment
     1287     * @param way2Node1 The first node of the second WaySegment
     1288     * @param way2Node2 The second node of the second WaySegment
     1289     * @return The distance between the two {@link WaySegment}s in meters
     1290     * (or the unit of the current projection, see {@link Projection}).
     1291     * @since xxx
     1292     */
     1293    public static double getDistanceSegmentSegment(Node way1Node1, Node way1Node2, Node way2Node1, Node way2Node2) {
     1294        EastNorth vectorOne = way1Node2.getEastNorth().subtract(way1Node1.getEastNorth());
     1295        EastNorth vectorTwo = way2Node2.getEastNorth().subtract(way2Node1.getEastNorth());
     1296        EastNorth vectorThree = way1Node1.getEastNorth().subtract(way2Node1.getEastNorth());
     1297        double smallNumber = 0.00000000001;
     1298        double a = dot(vectorOne, vectorOne);
     1299        double b = dot(vectorOne, vectorTwo);
     1300        double c = dot(vectorTwo, vectorTwo);
     1301        double d = dot(vectorOne, vectorThree);
     1302        double e = dot(vectorTwo, vectorThree);
     1303
     1304        double dotCombination = a * c - b * b;
     1305        double sc;
     1306        double sN;
     1307        double sD = d;
     1308        double tc;
     1309        double tN;
     1310        double tD = dotCombination;
     1311        if (dotCombination < smallNumber) {
     1312            sN = 0.0;
     1313            sD = 1.0;
     1314            tN = e;
     1315            tD = c;
     1316        } else {
     1317            sN = (b * e - c * d);
     1318            tN = (a * e - b * d);
     1319            if (sN < 0.0) {
     1320                sN = 0.0;
     1321                tN = e;
     1322                tD = c;
     1323            } else if (sN > sD) {
     1324                sN = sD;
     1325                tN = e + b;
     1326                tD = c;
     1327            }
     1328        }
     1329
     1330        if (tN < 0.0) {
     1331            tN = 0.0;
     1332            if (-d < 0.0) sN = 0.0;
     1333            else if (-d > a) sN = sD;
     1334            else {
     1335                sN = -d;
     1336                sD = a;
     1337            }
     1338        } else if (tN > tD) {
     1339            tN = tD;
     1340            if ((-d + b) < 0.0) sN = 0;
     1341            else if ((-d + b) > a) sN = sD;
     1342            else {
     1343                sN = (-d + b);
     1344                sD = a;
     1345            }
     1346        }
     1347        sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD;
     1348        tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD;
     1349        EastNorth p1 = way1Node1.getEastNorth().interpolate(way1Node2.getEastNorth(), sc);
     1350        EastNorth p2 = way2Node1.getEastNorth().interpolate(way2Node2.getEastNorth(), tc);
     1351        return p1.distance(p2);
     1352    }
     1353
     1354    /**
     1355     * Get the dot product of two different EastNorth points
     1356     * @param one The originating EastNorth
     1357     * @param two The final EastNorth
     1358     * @return the dot product of the EastNorths
     1359     * @since xxx
     1360     */
     1361    public static double dot(EastNorth one, EastNorth two) {
     1362        return two.getX() * one.getX() + one.getY() * two.getY();
     1363    }
    10731364}
  • 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.MAX_VALUE, distance, 0.1);
     187
     188        distance = Geometry.getDistance(way1, null);
     189        assertEquals(Double.MAX_VALUE, distance, 0.1);
     190
     191        distance = Geometry.getDistance(null, null);
     192        assertEquals(Double.MAX_VALUE, 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}