Ticket #17616: 17616_v5.patch

File 17616_v5.patch, 24.2 KB (added by taylor.smock, 5 years ago)

Add synchronized statements for waySegments to avoid thread safety issues. Even if something clears waySegments, the user should still get data.

  • 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;
     15import java.util.HashMap;
    1416import java.util.LinkedHashSet;
    1517import java.util.List;
    1618import java.util.Set;
     
    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;
     
    4448 * @author viesturs
    4549 */
    4650public final class Geometry {
     51    /** A holding map to store calculated {@link WaySegment}s in */
     52    static final HashMap<Way, List<WaySegment>> waySegments = new HashMap<>();
    4753
    4854    private Geometry() {
    4955        // Hide default constructor for utils classes
     
    10701076        }
    10711077        return new AreaAndPerimeter(Math.abs(area) / 2, perimeter);
    10721078    }
     1079
     1080    /**
     1081     * Get the closest primitive to {@code osm} from the collection of OsmPrimitive {@code primitives}
     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 {@code OsmPrimitive}
     1085     * @since xxx
     1086     */
     1087    public static OsmPrimitive getClosestPrimitive(OsmPrimitive osm, Collection<OsmPrimitive> primitives) {
     1088        double lowestDistance = Double.MAX_VALUE;
     1089        OsmPrimitive closest = null;
     1090        for (OsmPrimitive primitive : primitives) {
     1091            double distance = getDistance(osm, primitive);
     1092            if (distance < lowestDistance) {
     1093                lowestDistance = distance;
     1094                closest = primitive;
     1095            }
     1096        }
     1097        clearCachedWaySegments(primitives.toArray(new Way[0]));
     1098        return closest;
     1099    }
     1100
     1101    /**
     1102     * Get the furthest primitive to {@code osm} from the collection of OsmPrimitive {@code primitives}
     1103     * @param osm The primitive to get the distances from
     1104     * @param primitives The collection of primitives to get the distance to
     1105     * @return The furthest {@code OsmPrimitive}
     1106     * @since xxx
     1107     */
     1108    public static OsmPrimitive getFurthestPrimitive(OsmPrimitive osm, Collection<OsmPrimitive> primitives) {
     1109        double furthestDistance = Double.NEGATIVE_INFINITY;
     1110        OsmPrimitive furthest = null;
     1111        for (OsmPrimitive primitive : primitives) {
     1112            double distance = getDistance(osm, primitive);
     1113            if (distance > furthestDistance) {
     1114                furthestDistance = distance;
     1115                furthest = primitive;
     1116            }
     1117        }
     1118        clearCachedWaySegments(primitives.toArray(new Way[0]));
     1119        return furthest;
     1120    }
     1121
     1122    /**
     1123     * Get the distance between different {@code OsmPrimitive}s
     1124     * @param one The primitive to get the distance from
     1125     * @param two The primitive to get the distance to
     1126     * @return The distance between the primitives
     1127     * @since xxx
     1128     */
     1129    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1130        double rValue = Double.MAX_VALUE;
     1131        if (one == null || two == null) return rValue;
     1132        if (one instanceof Node && two instanceof Node) {
     1133            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1134        } else if (one instanceof Node && two instanceof Way) {
     1135            rValue = getDistanceWayNode((Way) two, (Node) one);
     1136        } else if (one instanceof Way && two instanceof Node) {
     1137            rValue = getDistanceWayNode((Way) one, (Node) two);
     1138        } else if (one instanceof Way && two instanceof Way) {
     1139            rValue = getDistanceWayWay((Way) one, (Way) two);
     1140        } else if (one instanceof Relation && !(two instanceof Relation)) {
     1141            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1142                double currentDistance = getDistance(osmPrimitive, two);
     1143                if (currentDistance < rValue) rValue = currentDistance;
     1144            }
     1145        } else if (!(one instanceof Relation) && two instanceof Relation) {
     1146            for (OsmPrimitive osmPrimitive : ((Relation) two).getMemberPrimitives()) {
     1147                double currentDistance = getDistance(osmPrimitive, one);
     1148                if (currentDistance < rValue) rValue = currentDistance;
     1149            }
     1150        } else if (one instanceof Relation && two instanceof Relation) {
     1151            for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) {
     1152                for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) {
     1153                    double currentDistance = getDistance(osmPrimitive1, osmPrimitive2);
     1154                    if (currentDistance < rValue) rValue = currentDistance;
     1155                }
     1156            }
     1157        }
     1158        return rValue;
     1159    }
     1160
     1161    /**
     1162     * Get the distance between a way and a node
     1163     * @param way The way to get the distance from
     1164     * @param node The node to get the distance to
     1165     * @return The distance between the {@code way} and the {@code node}
     1166     * @since xxx
     1167     */
     1168    public static double getDistanceWayNode(Way way, Node node) {
     1169        double rValue = Double.MAX_VALUE;
     1170        if (way.getNodesCount() < 2) return rValue;
     1171        List<WaySegment> segments = getWaySegments(way);
     1172        for (WaySegment segment : segments) {
     1173            EastNorth point = Geometry.closestPointToSegment(segment.getFirstNode().getEastNorth(), segment.getSecondNode().getEastNorth(), node.getEastNorth());
     1174            double distance = point.distance(node.getEastNorth());
     1175            if (distance < rValue) rValue = distance;
     1176        }
     1177        return rValue;
     1178    }
     1179
     1180    /**
     1181     * Get the closest {@code WaySegment} from a way to a primitive
     1182     * @param way The {@code Way} to get the distance from and the {@code WaySegment}
     1183     * @param primitive The {@code Primitive} to get the distance to
     1184     * @return The {@code WaySegment} that is closest to {@code primitive} from {@code way}
     1185     * @since xxx
     1186     */
     1187    public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) {
     1188        List<WaySegment> segments = getWaySegments(way);
     1189        double lowestDistance = Double.MAX_VALUE;
     1190        WaySegment closest = null;
     1191        for (WaySegment segment : segments) {
     1192            double distance = getDistance(segment.toWay(), primitive);
     1193            if (distance < lowestDistance) {
     1194                lowestDistance = distance;
     1195                closest = segment;
     1196            }
     1197        }
     1198        return closest;
     1199    }
     1200
     1201    /**
     1202     * Get the distance between different ways
     1203     * @param one The way to get the distance from
     1204     * @param two The {@code Way} to get the distance to
     1205     * @return The shortest distance between the ways
     1206     * @since xxx
     1207     */
     1208    public static double getDistanceWayWay(Way one, Way two) {
     1209        double rValue = Double.MAX_VALUE;
     1210        List<WaySegment> oneSegments = getWaySegments(one);
     1211        List<WaySegment> twoSegments = getWaySegments(two);
     1212        for (WaySegment oneSegment : oneSegments) {
     1213            for (WaySegment twoSegment : twoSegments) {
     1214                EastNorth en1 = oneSegment.getFirstNode().getEastNorth();
     1215                EastNorth en2 = oneSegment.getSecondNode().getEastNorth();
     1216                EastNorth en3 = twoSegment.getFirstNode().getEastNorth();
     1217                EastNorth en4 = twoSegment.getSecondNode().getEastNorth();
     1218                if (en1 == null || en2 == null || en3 == null || en4 == null) continue;
     1219                EastNorth intersection = Geometry.getSegmentSegmentIntersection(
     1220                        en1, en2, en3, en4);
     1221                if (intersection != null) return 0.0;
     1222                double distance = getDistanceSegmentSegment(oneSegment, twoSegment);
     1223                if (distance < rValue) rValue = distance;
     1224            }
     1225        }
     1226        return rValue;
     1227    }
     1228
     1229    /**
     1230     * Get the distance between different {@code WaySegment}s
     1231     * @param one A {@code WaySegment} to get the distance from
     1232     * @param two A {@code WaySegment} to get the distance to
     1233     * @return The distance between the two {@code WaySegment}s
     1234     * @since xxx
     1235     */
     1236    public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) {
     1237        EastNorth vectorOne = one.getSecondNode().getEastNorth().subtract(one.getFirstNode().getEastNorth());
     1238        EastNorth vectorTwo = two.getSecondNode().getEastNorth().subtract(two.getFirstNode().getEastNorth());
     1239        EastNorth vectorThree = one.getFirstNode().getEastNorth().subtract(two.getFirstNode().getEastNorth());
     1240        double smallNumber = 0.00000000001;
     1241        double a = dot(vectorOne, vectorOne);
     1242        double b = dot(vectorOne, vectorTwo);
     1243        double c = dot(vectorTwo, vectorTwo);
     1244        double d = dot(vectorOne, vectorThree);
     1245        double e = dot(vectorTwo, vectorThree);
     1246
     1247        double dotCombination = a * c - b * b;
     1248        double sc;
     1249        double sN;
     1250        double sD = d;
     1251        double tc;
     1252        double tN;
     1253        double tD = dotCombination;
     1254        if (dotCombination < smallNumber) {
     1255            sN = 0.0;
     1256            sD = 1.0;
     1257            tN = e;
     1258            tD = c;
     1259        } else {
     1260            sN = (b * e - c * d);
     1261            tN = (a * e - b * d);
     1262            if (sN < 0.0) {
     1263                sN = 0.0;
     1264                tN = e;
     1265                tD = c;
     1266            } else if (sN > sD) {
     1267                sN = sD;
     1268                tN = e + b;
     1269                tD = c;
     1270            }
     1271        }
     1272
     1273        if (tN < 0.0) {
     1274            tN = 0.0;
     1275            if (-d < 0.0) sN = 0.0;
     1276            else if (-d > a) sN = sD;
     1277            else {
     1278                sN = -d;
     1279                sD = a;
     1280            }
     1281        } else if (tN > tD) {
     1282            tN = tD;
     1283            if ((-d + b) < 0.0) sN = 0;
     1284            else if ((-d + b) > a) sN = sD;
     1285            else {
     1286                sN = (-d + b);
     1287                sD = a;
     1288            }
     1289        }
     1290        sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD;
     1291        tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD;
     1292        EastNorth p1 = one.getFirstNode().getEastNorth().interpolate(one.getSecondNode().getEastNorth(), sc);
     1293        EastNorth p2 = two.getFirstNode().getEastNorth().interpolate(two.getSecondNode().getEastNorth(), tc);
     1294        return p1.distance(p2);
     1295    }
     1296
     1297    /**
     1298     * Get the dot product of two different EastNorth points
     1299     * @param one The originating EastNorth
     1300     * @param two The final EastNorth
     1301     * @return the dot product of the EastNorths
     1302     * @since xxx
     1303     */
     1304    public static double dot(EastNorth one, EastNorth two) {
     1305        return two.getX() * one.getX() + one.getY() * two.getY();
     1306    }
     1307
     1308    /**
     1309     * Get the way segments of a way
     1310     * @param way The way to get the way segments of
     1311     * @return A list of {@code WaySegment}s
     1312     * @since xxx
     1313     */
     1314    public static List<WaySegment> getWaySegments(Way way) {
     1315        synchronized (waySegments) {
     1316            if (waySegments.containsKey(way) && !way.isModified())
     1317                return waySegments.get(way);
     1318        }
     1319        List<WaySegment> segments = new ArrayList<>();
     1320        int i = 0;
     1321        do {
     1322            segments.add(new WaySegment(way, i));
     1323            i++;
     1324        } while (i < way.getNodesCount() - 2);
     1325        synchronized (waySegments) {
     1326            waySegments.put(way, segments);
     1327        }
     1328        return segments;
     1329    }
     1330
     1331    /**
     1332     * Call to clear cached way segments for performance
     1333     * @since xxx
     1334     */
     1335    public static void clearCachedWaySegments() {
     1336        synchronized (waySegments) {
     1337            waySegments.clear();
     1338        }
     1339    }
     1340
     1341    /**
     1342     * Clear the cached way segments of a way
     1343     * @param ways The ways to remove from the cached way segments
     1344     * @since xxx
     1345     */
     1346    public static void clearCachedWaySegments(Way... ways) {
     1347        synchronized (waySegments) {
     1348            for (Way way : ways) {
     1349                waySegments.remove(way);
     1350            }
     1351        }
     1352    }
    10731353}
  • 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));
     172        Node node3 = new Node(new LatLon(1, 0));
     173        Node node4 = new Node(new LatLon(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(111319.49079327357, distance, 0.1);
     196
     197        distance = Geometry.getDistance(way1, node3);
     198        assertEquals(111325.1428663855, distance, 0.1);
     199
     200        distance = Geometry.getDistance(node3, way1);
     201        assertEquals(111325.1428663855, distance, 0.1);
     202
     203        distance = Geometry.getDistance(way1, way2);
     204        assertEquals(111325.1428663855, distance, 0.1);
     205
     206        distance = Geometry.getDistance(testRelation1, new Node(new LatLon(0, 0.5)));
     207        assertEquals(0.0, distance, 0.1);
     208
     209        distance = Geometry.getDistance(new Node(new LatLon(0, 0.5)), testRelation1);
     210        assertEquals(0.0, 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));
     223        Node node3 = new Node(new LatLon(1, 0));
     224        Node node4 = new Node(new LatLon(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));
     242        Node node3 = new Node(new LatLon(1, 0));
     243        Node node4 = new Node(new LatLon(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(1, 0));
     270        Node node4 = new Node(new LatLon(1, 1));
     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}