Ticket #17616: 17616-v9.patch

File 17616-v9.patch, 30.5 KB (added by GerdP, 6 years ago)

adapted to r15031, additional unit test and alternative simpler but slower implementation for getDistanceSegmentSegment()

  • 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

     
    99import java.math.BigDecimal;
    1010import java.math.MathContext;
    1111import java.util.ArrayList;
     12import java.util.Collection;
    1213import java.util.Collections;
    1314import java.util.Comparator;
    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;
     
    11021106        }
    11031107        return new AreaAndPerimeter(Math.abs(area) / 2, perimeter);
    11041108    }
     1109
     1110    /**
     1111     * Get the closest primitive to {@code osm} from the collection of
     1112     * OsmPrimitive {@code primitives}
     1113     *
     1114     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1115     *
     1116     * @param <T> The return type of the primitive
     1117     * @param osm The primitive to get the distances from
     1118     * @param primitives The collection of primitives to get the distance to
     1119     * @return The closest {@link OsmPrimitive}. This is not determinative.
     1120     * To get all primitives that share the same distance, use
     1121     * {@link Geometry#getClosestPrimitives}.
     1122     * @since xxx
     1123     */
     1124    public static <T extends OsmPrimitive> T getClosestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1125        Collection<T> collection = getClosestPrimitives(osm, primitives);
     1126        return collection.iterator().next();
     1127    }
     1128
     1129    /**
     1130     * Get the closest primitives to {@code osm} from the collection of
     1131     * OsmPrimitive {@code primitives}
     1132     *
     1133     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1134     *
     1135     * @param <T> The return type of the primitive
     1136     * @param osm The primitive to get the distances from
     1137     * @param primitives The collection of primitives to get the distance to
     1138     * @return The closest {@link OsmPrimitive}s. May be empty.
     1139     * @since xxx
     1140     */
     1141    public static <T extends OsmPrimitive> Collection<T> getClosestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1142        double lowestDistance = Double.MAX_VALUE;
     1143        TreeSet<T> closest = new TreeSet<>();
     1144        for (T primitive : primitives) {
     1145            double distance = getDistance(osm, primitive);
     1146            if (Double.isNaN(distance)) continue;
     1147            if (distance < lowestDistance) {
     1148                closest.clear();
     1149                lowestDistance = distance;
     1150                closest.add(primitive);
     1151            } else if (distance == lowestDistance) {
     1152                closest.add(primitive);
     1153            }
     1154        }
     1155        return closest;
     1156    }
     1157
     1158    /**
     1159     * Get the furthest primitive to {@code osm} from the collection of
     1160     * OsmPrimitive {@code primitives}
     1161     *
     1162     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1163     *
     1164     * It does NOT give the furthest primitive based off of the furthest
     1165     * part of that primitive
     1166     * @param <T> The return type of the primitive
     1167     * @param osm The primitive to get the distances from
     1168     * @param primitives The collection of primitives to get the distance to
     1169     * @return The furthest {@link OsmPrimitive}.  This is not determinative.
     1170     * To get all primitives that share the same distance, use
     1171     * {@link Geometry#getFurthestPrimitives}
     1172     * @since xxx
     1173     */
     1174    public static <T extends OsmPrimitive> T getFurthestPrimitive(OsmPrimitive osm, Collection<T> primitives) {
     1175        return getFurthestPrimitives(osm, primitives).iterator().next();
     1176    }
     1177
     1178    /**
     1179     * Get the furthest primitives to {@code osm} from the collection of
     1180     * OsmPrimitive {@code primitives}
     1181     *
     1182     * The {@code primitives} should be fully downloaded to ensure accuracy.
     1183     *
     1184     * It does NOT give the furthest primitive based off of the furthest
     1185     * part of that primitive
     1186     * @param <T> The return type of the primitive
     1187     * @param osm The primitive to get the distances from
     1188     * @param primitives The collection of primitives to get the distance to
     1189     * @return The furthest {@link OsmPrimitive}s. It may return an empty collection.
     1190     * @since xxx
     1191     */
     1192    public static <T extends OsmPrimitive> Collection<T> getFurthestPrimitives(OsmPrimitive osm, Collection<T> primitives) {
     1193        double furthestDistance = Double.NEGATIVE_INFINITY;
     1194        TreeSet<T> furthest = new TreeSet<>();
     1195        for (T primitive : primitives) {
     1196            double distance = getDistance(osm, primitive);
     1197            if (Double.isNaN(distance)) continue;
     1198            if (distance > furthestDistance) {
     1199                furthest.clear();
     1200                furthestDistance = distance;
     1201                furthest.add(primitive);
     1202            } else if (distance == furthestDistance) {
     1203                furthest.add(primitive);
     1204            }
     1205        }
     1206        return furthest;
     1207    }
     1208
     1209    /**
     1210     * Get the distance between different {@link OsmPrimitive}s
     1211     * @param one The primitive to get the distance from
     1212     * @param two The primitive to get the distance to
     1213     * @return The distance between the primitives in meters
     1214     * (or the unit of the current projection, see {@link Projection}).
     1215     * May return {@link Double#NaN} if one of the primitives is incomplete.
     1216     * @since xxx
     1217     */
     1218    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1219        double rValue = Double.MAX_VALUE;
     1220        if (one == null || two == null || one.isIncomplete()
     1221                || two.isIncomplete()) return Double.NaN;
     1222        if (one instanceof Node && two instanceof Node) {
     1223            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1224        } else if (one instanceof Node && two instanceof Way) {
     1225            rValue = getDistanceWayNode((Way) two, (Node) one);
     1226        } else if (one instanceof Way && two instanceof Node) {
     1227            rValue = getDistanceWayNode((Way) one, (Node) two);
     1228        } else if (one instanceof Way && two instanceof Way) {
     1229            rValue = getDistanceWayWay((Way) one, (Way) two);
     1230        } else if (one instanceof Relation && !(two instanceof Relation)) {
     1231            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1232                double currentDistance = getDistance(osmPrimitive, two);
     1233                if (currentDistance < rValue) rValue = currentDistance;
     1234            }
     1235        } else if (!(one instanceof Relation) && two instanceof Relation) {
     1236            for (OsmPrimitive osmPrimitive : ((Relation) two).getMemberPrimitives()) {
     1237                double currentDistance = getDistance(osmPrimitive, one);
     1238                if (currentDistance < rValue) rValue = currentDistance;
     1239            }
     1240        } else if (one instanceof Relation && two instanceof Relation) {
     1241            for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) {
     1242                for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) {
     1243                    double currentDistance = getDistance(osmPrimitive1, osmPrimitive2);
     1244                    if (currentDistance < rValue) rValue = currentDistance;
     1245                }
     1246            }
     1247        }
     1248        return rValue;
     1249    }
     1250
     1251    /**
     1252     * Get the distance between a way and a node
     1253     * @param way The way to get the distance from
     1254     * @param node The node to get the distance to
     1255     * @return The distance between the {@code way} and the {@code node} in
     1256     * meters (or the unit of the current projection, see {@link Projection}).
     1257     * May return {@link Double#NaN} if the primitives are incomplete.
     1258     * @since xxx
     1259     */
     1260    public static double getDistanceWayNode(Way way, Node node) {
     1261        if (way == null || node == null || way.isIncomplete()
     1262                || node.isIncomplete()) return Double.NaN;
     1263        double rValue = Double.MAX_VALUE;
     1264        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1265            EastNorth point = Geometry.closestPointToSegment(
     1266                    nodes.a.getEastNorth(), nodes.b.getEastNorth(),
     1267                    node.getEastNorth());
     1268            double distance = point.distance(node.getEastNorth());
     1269            if (distance < rValue) rValue = distance;
     1270        }
     1271        return rValue;
     1272    }
     1273
     1274    /**
     1275     * Get the closest {@link WaySegment} from a way to a primitive.
     1276     * @param way The {@link Way} to get the distance from and the {@link WaySegment}
     1277     * @param primitive The {@link OsmPrimitive} to get the distance to
     1278     * @return The {@link WaySegment} that is closest to {@code primitive} from {@code way}.
     1279     * If there are multiple {@link WaySegment}s with the same distance, the last
     1280     * {@link WaySegment} with the same distance will be returned.
     1281     * May return {@code null} if the way has fewer than two nodes or one
     1282     * of the primitives is incomplete.
     1283     * @since xxx
     1284     */
     1285    public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) {
     1286        if (way == null || primitive == null || way.isIncomplete()
     1287                || primitive.isIncomplete()) return null;
     1288        double lowestDistance = Double.MAX_VALUE;
     1289        Pair<Node, Node> closestNodes = null;
     1290        for (Pair<Node, Node> nodes : way.getNodePairs(false)) {
     1291            Way tWay = new Way();
     1292            tWay.addNode(nodes.a);
     1293            tWay.addNode(nodes.b);
     1294            double distance = getDistance(tWay, primitive);
     1295            if (distance < lowestDistance) {
     1296                lowestDistance = distance;
     1297                closestNodes = nodes;
     1298            }
     1299        }
     1300        if (closestNodes == null) return null;
     1301        return WaySegment.forNodePair(way, closestNodes.a, closestNodes.b);
     1302    }
     1303
     1304    /**
     1305     * Get the distance between different ways
     1306     * @param one The way to get the distance from
     1307     * @param two The {@link Way} to get the distance to
     1308     * @return The shortest distance between the ways in meters
     1309     * (or the unit of the current projection, see {@link Projection}).
     1310     * May return {@link Double#NaN}.
     1311     * @since xxx
     1312     */
     1313    public static double getDistanceWayWay(Way one, Way two) {
     1314        if (one == null || two == null || one.isIncomplete()
     1315                || two.isIncomplete()) return Double.NaN;
     1316
     1317        double rValue = Double.MAX_VALUE;
     1318        for (Pair<Node, Node> oneNodes : one.getNodePairs(false)) {
     1319            for (Pair<Node, Node> twoNodes : two.getNodePairs(false)) {
     1320                double distance = getDistanceSegmentSegment(oneNodes.a, oneNodes.b, twoNodes.a, twoNodes.b);
     1321                if (distance < rValue) rValue = distance;
     1322            }
     1323        }
     1324        return rValue;
     1325    }
     1326
     1327    /**
     1328     * Get the distance between different {@link WaySegment}s
     1329     * @param one A {@link WaySegment} to get the distance from
     1330     * @param two A {@link WaySegment} to get the distance to
     1331     * @return The distance between the two {@link WaySegment}s in meters
     1332     * (or the unit of the current projection, see {@link Projection}).
     1333     * May return {@link Double#NaN}.
     1334     * @since xxx
     1335     */
     1336    public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) {
     1337        return getDistanceSegmentSegment(one.getFirstNode(), one.getSecondNode(), two.getFirstNode(), two.getSecondNode());
     1338    }
     1339
     1340    /**
     1341     * Get the distance between different {@link WaySegment}s
     1342     * @param way1Node1 The first node of the first WaySegment
     1343     * @param way1Node2 The second node of the second WaySegment
     1344     * @param way2Node1 The first node of the second WaySegment
     1345     * @param way2Node2 The second node of the second WaySegment
     1346     * @return The distance between the two {@link WaySegment}s in meters
     1347     * (or the unit of the current projection, see {@link Projection}).
     1348     * May return {@link Double#NaN}.
     1349     * @since xxx
     1350     */
     1351    public static double getDistanceSegmentSegment(Node way1Node1, Node way1Node2, Node way2Node1, Node way2Node2) {
     1352        EastNorth enWay1Node1 = way1Node1.getEastNorth();
     1353        EastNorth enWay1Node2 = way1Node2.getEastNorth();
     1354        EastNorth enWay2Node1 = way2Node1.getEastNorth();
     1355        EastNorth enWay2Node2 = way2Node2.getEastNorth();
     1356        if (enWay1Node1 == null || enWay1Node2 == null || enWay2Node1 == null || enWay2Node2 == null)
     1357            return Double.NaN;
     1358        if (getSegmentSegmentIntersection(enWay1Node1, enWay1Node2, enWay2Node1, enWay2Node2) != null)
     1359            return 0;
     1360
     1361        EastNorth vectorOne = enWay1Node2.subtract(enWay1Node1);
     1362        EastNorth vectorTwo = enWay2Node2.subtract(enWay2Node1);
     1363        EastNorth vectorThree = enWay1Node1.subtract(enWay2Node1);
     1364        double smallNumber = 0.00000000001;
     1365        double a = dot(vectorOne, vectorOne);
     1366        double b = dot(vectorOne, vectorTwo);
     1367        double c = dot(vectorTwo, vectorTwo);
     1368        double d = dot(vectorOne, vectorThree);
     1369        double e = dot(vectorTwo, vectorThree);
     1370
     1371        double dotCombination = a * c - b * b;
     1372        double sc;
     1373        double sN;
     1374        double sD = d;
     1375        double tc;
     1376        double tN;
     1377        double tD = dotCombination;
     1378        if (dotCombination < smallNumber) {
     1379            sN = 0.0;
     1380            sD = 1.0;
     1381            tN = e;
     1382            tD = c;
     1383        } else {
     1384            sN = (b * e - c * d);
     1385            tN = (a * e - b * d);
     1386            if (sN < 0.0) {
     1387                sN = 0.0;
     1388                tN = e;
     1389                tD = c;
     1390            } else if (sN > sD) {
     1391                sN = sD;
     1392                tN = e + b;
     1393                tD = c;
     1394            }
     1395        }
     1396
     1397        if (tN < 0.0) {
     1398            tN = 0.0;
     1399            if (-d < 0.0) sN = 0.0;
     1400            else if (-d > a) sN = sD;
     1401            else {
     1402                sN = -d;
     1403                sD = a;
     1404            }
     1405        } else if (tN > tD) {
     1406            tN = tD;
     1407            if ((-d + b) < 0.0) sN = 0;
     1408            else if ((-d + b) > a) sN = sD;
     1409            else {
     1410                sN = (-d + b);
     1411                sD = a;
     1412            }
     1413        }
     1414        sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD;
     1415        tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD;
     1416        EastNorth p1 = enWay1Node1.interpolate(enWay1Node2, sc);
     1417        EastNorth p2 = enWay2Node1.interpolate(enWay2Node2, tc);
     1418        return p1.distance(p2);
     1419    }
     1420
     1421    /**
     1422     * Get the dot product of two different EastNorth points
     1423     * @param one The originating EastNorth
     1424     * @param two The final EastNorth
     1425     * @return the dot product of the EastNorths
     1426     * @since xxx
     1427     */
     1428    public static double dot(EastNorth one, EastNorth two) {
     1429        return two.getX() * one.getX() + one.getY() * two.getY();
     1430    }
     1431
     1432    /**
     1433     * Get the distance between different {@link WaySegment}s
     1434     * @param way1Node1 The first node of the first WaySegment
     1435     * @param way1Node2 The second node of the second WaySegment
     1436     * @param way2Node1 The first node of the second WaySegment
     1437     * @param way2Node2 The second node of the second WaySegment
     1438     * @return The distance between the two {@link WaySegment}s in meters
     1439     * (or the unit of the current projection, see {@link Projection}).
     1440     * May return {@link Double#NaN}.
     1441     * @since xxx
     1442     */
     1443    public static double getDistanceSegmentSegmentSlow(Node way1Node1, Node way1Node2, Node way2Node1, Node way2Node2) {
     1444        EastNorth enWay1Node1 = way1Node1.getEastNorth();
     1445        EastNorth enWay1Node2 = way1Node2.getEastNorth();
     1446        EastNorth enWay2Node1 = way2Node1.getEastNorth();
     1447        EastNorth enWay2Node2 = way2Node2.getEastNorth();
     1448        if (enWay1Node1 == null || enWay1Node2 == null || enWay2Node1 == null || enWay2Node2 == null)
     1449            return Double.NaN;
     1450        if (Geometry.getSegmentSegmentIntersection(enWay1Node1, enWay1Node2, enWay2Node1, enWay2Node2) != null)
     1451            return 0;
     1452
     1453        double dist = Geometry.getNodeSegmentDist(enWay1Node1, enWay1Node2, enWay2Node1);
     1454        dist = Math.min(dist, getNodeSegmentDist(enWay1Node1, enWay1Node2, enWay2Node2));
     1455        dist = Math.min(dist, getNodeSegmentDist(enWay2Node1, enWay2Node2, enWay1Node1));
     1456        dist = Math.min(dist, getNodeSegmentDist(enWay2Node1, enWay2Node2, enWay1Node2));
     1457        return dist;
     1458    }
     1459
     1460    private static double getNodeSegmentDist(EastNorth s1, EastNorth s2, EastNorth p) {
     1461        EastNorth c1 = Geometry.closestPointTo(s1, s2, p, true);
     1462        return c1.distance(p);
     1463    }
     1464
    11051465}
  • test/unit/org/openstreetmap/josm/tools/GeometryTest.java

     
    77import static org.junit.Assert.assertTrue;
    88
    99import java.io.FileInputStream;
     10import java.util.ArrayList;
    1011import java.util.Arrays;
    1112import java.util.List;
    1213
     
    1819import org.openstreetmap.josm.data.coor.LatLon;
    1920import org.openstreetmap.josm.data.osm.DataSet;
    2021import org.openstreetmap.josm.data.osm.Node;
     22import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2123import org.openstreetmap.josm.data.osm.Relation;
    2224import org.openstreetmap.josm.data.osm.RelationMember;
    2325import org.openstreetmap.josm.data.osm.Way;
     
    258260        // now w1 is inside
    259261        assertTrue(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp, null));
    260262    }
     263
     264    /**
     265     * Test of {@link Geometry#getDistance} method.
     266     */
     267    @Test
     268    public void testGetDistance() {
     269        Node node1 = new Node(new LatLon(0, 0));
     270        Node node2 = new Node(new LatLon(0.1, 1));
     271        Node node3 = new Node(new LatLon(1.1, 0.1));
     272        Node node4 = new Node(new LatLon(1, 1.1));
     273        Way way1 = TestUtils.newWay("", node1, node2);
     274        Way way2 = TestUtils.newWay("", node3, node4);
     275        Relation testRelation1 = new Relation();
     276        Relation testRelation2 = new Relation();
     277        testRelation1.addMember(new RelationMember("", way1));
     278        testRelation1.addMember(new RelationMember("", way2));
     279        testRelation2.addMember(new RelationMember("", node1));
     280        testRelation2.addMember(new RelationMember("", node2));
     281        testRelation2.addMember(new RelationMember("", node3));
     282        testRelation2.addMember(new RelationMember("", node4));
     283
     284        double distance = Geometry.getDistance(null, node3);
     285        assertEquals(Double.NaN, distance, 0.1);
     286
     287        distance = Geometry.getDistance(way1, null);
     288        assertEquals(Double.NaN, distance, 0.1);
     289
     290        distance = Geometry.getDistance(null, null);
     291        assertEquals(Double.NaN, distance, 0.1);
     292
     293        distance = Geometry.getDistance(node1, node2);
     294        assertEquals(111874.6474307704, distance, 0.1);
     295
     296        distance = Geometry.getDistance(way1, node3);
     297        assertEquals(120743.55085962385, distance, 0.1);
     298
     299        distance = Geometry.getDistance(node3, way1);
     300        assertEquals(120743.55085962385, distance, 0.1);
     301
     302        distance = Geometry.getDistance(way1, way2);
     303        assertEquals(100803.63714283936, distance, 0.1);
     304
     305        distance = Geometry.getDistance(testRelation1, new Node(new LatLon(0, 0.5)));
     306        assertEquals(5538.354450686605, distance, 0.1);
     307
     308        distance = Geometry.getDistance(new Node(new LatLon(0, 0.5)), testRelation1);
     309        assertEquals(5538.354450686605, distance, 0.1);
     310
     311        distance = Geometry.getDistance(testRelation1, testRelation2);
     312        assertEquals(0.0, distance, 0.1);
     313    }
     314
     315    /**
     316     * Test of {@link Geometry#getClosestPrimitive} method
     317     */
     318    @Test
     319    public void testGetClosestPrimitive() {
     320        Node node1 = new Node(new LatLon(0, 0));
     321        Node node2 = new Node(new LatLon(0.1, 1));
     322        Node node3 = new Node(new LatLon(1.1, 0.1));
     323        Node node4 = new Node(new LatLon(1, 1.1));
     324        Way way1 = TestUtils.newWay("", node1, node2);
     325        Way way2 = TestUtils.newWay("", node3, node4);
     326
     327        List<OsmPrimitive> primitives = new ArrayList<>();
     328        primitives.add(way1);
     329        primitives.add(way2);
     330        OsmPrimitive closest = Geometry.getClosestPrimitive(node1, primitives);
     331        assertEquals(way1, closest);
     332    }
     333
     334    /**
     335     * Test of {@link Geometry#getFurthestPrimitive} method
     336     */
     337    @Test
     338    public void testGetFurthestPrimitive() {
     339        Node node1 = new Node(new LatLon(0, 0));
     340        Node node2 = new Node(new LatLon(0, 1.1));
     341        Node node3 = new Node(new LatLon(1, 0.1));
     342        Node node4 = new Node(new LatLon(1.1, 1));
     343        Way way1 = TestUtils.newWay("", node1, node2);
     344        Way way2 = TestUtils.newWay("", node3, node4);
     345        Way way3 = TestUtils.newWay("", node2, node4);
     346        Way way4 = TestUtils.newWay("", node1, node3);
     347
     348        List<OsmPrimitive> primitives = new ArrayList<>();
     349        primitives.add(way1);
     350        OsmPrimitive furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(0, 0.75)), primitives);
     351        assertEquals(way1, furthest);
     352        primitives.add(way2);
     353        primitives.add(way3);
     354        primitives.add(way4);
     355        furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(0, 0.5)), primitives);
     356        assertEquals(way2, furthest);
     357        furthest = Geometry.getFurthestPrimitive(new Node(new LatLon(.25, 0.5)), primitives);
     358        assertEquals(way2, furthest);
     359    }
     360
     361    /**
     362     * Test of {@link Geometry#getClosestWaySegment} method
     363     */
     364    @Test
     365    public void testGetClosestWaySegment() {
     366        Node node1 = new Node(new LatLon(0, 0));
     367        Node node2 = new Node(new LatLon(0, 1));
     368        Node node3 = new Node(new LatLon(0.3, 0.5));
     369        Node node4 = new Node(new LatLon(0.1, 0));
     370        Way way1 = TestUtils.newWay("", node1, node2, node3, node4);
     371
     372        Way closestSegment = Geometry.getClosestWaySegment(way1, new Node(new LatLon(0, 0.5))).toWay();
     373        Assert.assertTrue(closestSegment.containsNode(node1));
     374        Assert.assertTrue(closestSegment.containsNode(node2));
     375    }
     376
     377    /**
     378     * Test of {@link Geometry#getDistanceSegmentSegment} method
     379     */
     380    @Test
     381    public void testGetDistanceSegmentSegment() {
     382        Node node1 = new Node(new LatLon(2.0, 2.0));
     383        Node node2 = new Node(new LatLon(2.0, 3.0));
     384        Node node3 = new Node(new LatLon(2.3, 2.5));
     385        Node node4 = new Node(new LatLon(2.1, 2.0));
     386
     387        // connected segments
     388        assertEquals(0.0, Geometry.getDistanceSegmentSegment(node1, node2, node3, node1), 0.000001);
     389
     390        // distance between node 1 and node4 is the shortest
     391        double expected = node1.getEastNorth().distance(node4.getEastNorth());
     392        assertEquals(expected, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     393
     394        // crossing segments
     395        node4.setCoor(new LatLon(1.9998192774806864, 2.0004056993230455));
     396        assertEquals(0, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     397
     398        // usual case
     399        node4.setCoor(new LatLon(2.0002098170882276, 2.0000778643530537));
     400        assertEquals(23.4, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 1.0);
     401
     402        // similar segments, reversed direction
     403        node3.setCoor(node2.getCoor());
     404        node4.setCoor(node1.getCoor());
     405        assertEquals(0.0, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     406
     407        // overlapping segments
     408        node3.setCoor(new LatLon(2.0, 2.2));
     409        node4.setCoor(new LatLon(2.0, 2.3));
     410        assertEquals(0.0, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     411
     412        // parallel segments, n1 and n3 at same longitude
     413        node3.setCoor(new LatLon(2.1, 2.0));
     414        node4.setCoor(new LatLon(2.1, 2.3));
     415        expected = node1.getEastNorth().distance(node3.getEastNorth());
     416        assertEquals(expected, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     417
     418        // parallel segments
     419        node3.setCoor(new LatLon(2.1, 2.1));
     420        assertEquals(expected, Geometry.getDistanceSegmentSegment(node1, node2, node3, node4), 0.000001);
     421    }
    261422}