Ticket #17388: 17388.geometry_sqrt_cache.patch

File 17388.geometry_sqrt_cache.patch, 11.9 KB (added by taylor.smock, 5 years ago)

Avoid new node, cache east north (only affects future runs), modify Geometry to avoid unnecessary Math.sqrt

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

     
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.data.gpx;
    33
    4 import org.openstreetmap.josm.data.osm.Node;
     4import java.util.OptionalDouble;
     5
    56import org.openstreetmap.josm.data.osm.OsmPrimitive;
     7import org.openstreetmap.josm.data.projection.ProjectionRegistry;
    68import org.openstreetmap.josm.tools.Geometry;
    79
    810/**
     
    2325     * @return The shortest distance
    2426     */
    2527    public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) {
    26         return gpxData.getTrackPoints()
    27                 .mapToDouble(tp -> Geometry.getDistance(p, new Node(tp.getCoor())))
    28                 .filter(x -> x >= 0)
    29                 .min().orElse(Double.MAX_VALUE);
     28        OptionalDouble min = gpxData.getTrackPoints().map(waypoint -> waypoint.getEastNorth(ProjectionRegistry.getProjection()))
     29                .mapToDouble(tp -> Geometry.getDistanceSq(p, tp))
     30                .filter(x -> x >= 0).min();
     31        return min.isPresent() ? Math.sqrt(min.getAsDouble()) : Double.MAX_VALUE;
    3032    }
    3133}
  • src/org/openstreetmap/josm/tools/Geometry.java

     
    13031303        double lowestDistance = Double.MAX_VALUE;
    13041304        TreeSet<T> closest = new TreeSet<>();
    13051305        for (T primitive : primitives) {
    1306             double distance = getDistance(osm, primitive);
     1306            double distance = getDistanceSq(osm, primitive);
    13071307            if (Double.isNaN(distance)) continue;
    13081308            int comp = Double.compare(distance, lowestDistance);
    13091309            if (comp < 0) {
     
    13671367        double furthestDistance = Double.NEGATIVE_INFINITY;
    13681368        TreeSet<T> furthest = new TreeSet<>();
    13691369        for (T primitive : primitives) {
    1370             double distance = getDistance(osm, primitive);
     1370            double distance = getDistanceSq(osm, primitive);
    13711371            if (Double.isNaN(distance)) continue;
    13721372            int comp = Double.compare(distance, furthestDistance);
    13731373            if (comp > 0) {
     
    13941394     * @since 15035
    13951395     */
    13961396    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1397        double distance = getDistanceSq(one, two);
     1398        return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN;
     1399    }
     1400
     1401    /**
     1402     * Get the distance squared between different {@link OsmPrimitive}s
     1403     * @param one The primitive to get the distance from
     1404     * @param two The primitive to get the distance to
     1405     * @return The distance squared between the primitives in meters
     1406     * (or the unit of the current projection, see {@link Projection}).
     1407     * May return {@link Double#NaN} if one of the primitives is incomplete.
     1408     *
     1409     * Note: The complexity is O(n*m), where (n,m) are the number of child
     1410     * objects the {@link OsmPrimitive}s have.
     1411     * @since xxx
     1412     */
     1413    public static double getDistanceSq(OsmPrimitive one, OsmPrimitive two) {
    13971414        double rValue = Double.MAX_VALUE;
    13981415        if (one == null || two == null || one.isIncomplete()
    13991416                || two.isIncomplete()) return Double.NaN;
    14001417        if (one instanceof Node && two instanceof Node) {
    1401             rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1418            rValue = Math.pow(((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor()), 2);
    14021419        } else if (one instanceof Node && two instanceof Way) {
    1403             rValue = getDistanceWayNode((Way) two, (Node) one);
     1420            rValue = getDistanceWayEastNorthSq((Way) two, ((Node) one).getEastNorth());
    14041421        } else if (one instanceof Way && two instanceof Node) {
    1405             rValue = getDistanceWayNode((Way) one, (Node) two);
     1422            rValue = getDistanceWayEastNorthSq((Way) one, ((Node) two).getEastNorth());
    14061423        } else if (one instanceof Way && two instanceof Way) {
    1407             rValue = getDistanceWayWay((Way) one, (Way) two);
     1424            rValue = getDistanceWayWaySq((Way) one, (Way) two);
    14081425        } else if (one instanceof Relation && !(two instanceof Relation)) {
    14091426            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
    1410                 double currentDistance = getDistance(osmPrimitive, two);
     1427                double currentDistance = getDistanceSq(osmPrimitive, two);
    14111428                if (currentDistance < rValue) rValue = currentDistance;
    14121429            }
    14131430        } else if (!(one instanceof Relation) && two instanceof Relation) {
    1414             rValue = getDistance(two, one);
     1431            rValue = getDistanceSq(two, one);
    14151432        } else if (one instanceof Relation && two instanceof Relation) {
    14161433            for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) {
    14171434                for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) {
    1418                     double currentDistance = getDistance(osmPrimitive1, osmPrimitive2);
     1435                    double currentDistance = getDistanceSq(osmPrimitive1, osmPrimitive2);
    14191436                    if (currentDistance < rValue) rValue = currentDistance;
    14201437                }
    14211438            }
     
    14241441    }
    14251442
    14261443    /**
     1444     * Get the distance between a {@link OsmPrimitive} and a position
     1445     * @param one The primitive to get the distance from
     1446     * @param two The EastNorth to get the distance to
     1447     * @return The distance between the objects in meters
     1448     * (or the unit of the current projection, see {@link Projection}).
     1449     * May return {@link Double#NaN} if one of the objects is incomplete.
     1450     *
     1451     * Note: The complexity is O(n*m), where (n,m) are the number of child
     1452     * objects the {@link OsmPrimitive} have.
     1453     * @since xxx
     1454     */
     1455    public static double getDistanceSq(OsmPrimitive one, EastNorth two) {
     1456        double rValue = Double.MAX_VALUE;
     1457        if (one == null || two == null || one.isIncomplete()
     1458                || !two.isValid()) return Double.NaN;
     1459        if (one instanceof Node) {
     1460            rValue = two.distanceSq(((Node) one).getEastNorth());
     1461        } else if (one instanceof Way) {
     1462            rValue = getDistanceWayEastNorthSq((Way) one, two);
     1463        } else if (one instanceof Relation) {
     1464            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1465                double currentDistance = getDistanceSq(osmPrimitive, two);
     1466                if (currentDistance < rValue) rValue = currentDistance;
     1467            }
     1468        }
     1469        return rValue != Double.MAX_VALUE ? rValue : Double.NaN;
     1470    }
     1471
     1472    /**
    14271473     * Get the distance between a way and a node
    14281474     * @param way The way to get the distance from
    14291475     * @param node The node to get the distance to
     
    14351481    public static double getDistanceWayNode(Way way, Node node) {
    14361482        if (way == null || node == null || way.getNodesCount() < 2 || !node.isLatLonKnown())
    14371483            return Double.NaN;
     1484        double distanceSq = getDistanceWayEastNorthSq(way, node.getEastNorth());
     1485        return distanceSq != Double.MAX_VALUE && !Double.isNaN(distanceSq) ? Math.sqrt(distanceSq) : distanceSq;
     1486    }
    14381487
     1488    /**
     1489     * Get the distance between a way and a node squared
     1490     * @param way The way to get the distance from
     1491     * @param eastNorth The EastNorth to get the distance to
     1492     * @return The distance between the {@code way} and the {@code eastnorth} in
     1493     * meters (or the unit of the current projection, see {@link Projection}).
     1494     * May return {@link Double#NaN} if the primitives are incomplete.
     1495     * @since xxx
     1496     */
     1497    public static double getDistanceWayEastNorthSq(Way way, EastNorth eastNorth) {
     1498        if (way == null || eastNorth == null || way.getNodesCount() < 2 || !eastNorth.isValid())
     1499            return Double.NaN;
     1500
    14391501        double smallest = Double.MAX_VALUE;
    1440         EastNorth en0 = node.getEastNorth();
    14411502        // go through the nodes as if they were paired
    14421503        Iterator<Node> iter = way.getNodes().iterator();
    14431504        EastNorth en1 = iter.next().getEastNorth();
    14441505        while (iter.hasNext()) {
    14451506            EastNorth en2 = iter.next().getEastNorth();
    1446             double distance = getSegmentNodeDistSq(en1, en2, en0);
     1507            double distance = getSegmentNodeDistSq(en1, en2, eastNorth);
    14471508            if (distance < smallest)
    14481509                smallest = distance;
    14491510            en1 = en2;
    14501511        }
    1451         return smallest != Double.MAX_VALUE ? Math.sqrt(smallest) : Double.NaN;
     1512        return smallest != Double.MAX_VALUE ? smallest : Double.NaN;
    14521513    }
    14531514
    14541515    /**
     
    14921553     * @since 15035
    14931554     */
    14941555    public static double getDistanceWayWay(Way w1, Way w2) {
     1556        double distance = getDistanceWayWaySq(w1, w2);
     1557        return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN;
     1558    }
     1559    /**
     1560     *
     1561     * Get the distance squared between different ways. Iterates over the nodes of the ways, complexity is O(n*m)
     1562     * (n,m giving the number of nodes)
     1563     * @param w1 The first {@link Way}
     1564     * @param w2 The second {@link Way}
     1565     * @return The shortest distance squared between the ways in meters
     1566     * (or the unit of the current projection, see {@link Projection}).
     1567     * May return {@link Double#NaN}.
     1568     * @since xxx
     1569     */
     1570    public static double getDistanceWayWaySq(Way w1, Way w2) {
    14951571        if (w1 == null || w2 == null || w1.getNodesCount() < 2 || w2.getNodesCount() < 2)
    14961572            return Double.NaN;
    14971573        double rValue = Double.MAX_VALUE;
     
    15031579            Node w2N1 = iter2.next();
    15041580            while (iter2.hasNext()) {
    15051581                Node w2N2 = iter2.next();
    1506                 double distance = getDistanceSegmentSegment(w1N1, w1N2, w2N1, w2N2);
     1582                double distance = getDistanceSegmentSegmentSq(w1N1, w1N2, w2N1, w2N2);
    15071583                if (distance < rValue)
    15081584                    rValue = distance;
    15091585                w2N1 = w2N2;
     
    15381614     * @since 15035
    15391615     */
    15401616    public static double getDistanceSegmentSegment(Node ws1Node1, Node ws1Node2, Node ws2Node1, Node ws2Node2) {
     1617        double distance = getDistanceSegmentSegmentSq(ws1Node1, ws1Node2, ws2Node1, ws2Node2);
     1618        return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN;
     1619    }
     1620    /**
     1621     * Get the distance squared between different {@link WaySegment}s
     1622     * @param ws1Node1 The first node of the first WaySegment
     1623     * @param ws1Node2 The second node of the second WaySegment
     1624     * @param ws2Node1 The first node of the second WaySegment
     1625     * @param ws2Node2 The second node of the second WaySegment
     1626     * @return The distance squared between the two {@link WaySegment}s in meters
     1627     * (or the unit of the current projection, see {@link Projection}).
     1628     * May return {@link Double#NaN}.
     1629     * @since xxx
     1630     */
     1631    public static double getDistanceSegmentSegmentSq(Node ws1Node1, Node ws1Node2, Node ws2Node1, Node ws2Node2) {
    15411632        EastNorth enWs1Node1 = ws1Node1.getEastNorth();
    15421633        EastNorth enWs1Node2 = ws1Node2.getEastNorth();
    15431634        EastNorth enWs2Node1 = ws2Node1.getEastNorth();
     
    15521643        double dist3sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node1);
    15531644        double dist4sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node2);
    15541645        double smallest = Math.min(Math.min(dist1sq, dist2sq), Math.min(dist3sq, dist4sq));
    1555         return smallest != Double.MAX_VALUE ? Math.sqrt(smallest) : Double.NaN;
     1646        return smallest != Double.MAX_VALUE ? smallest : Double.NaN;
    15561647    }
    1557 
    15581648    /**
    15591649     * Calculate closest distance between a line segment s1-s2 and a point p
    15601650     * @param s1 start of segment