Changeset 18589 in josm for trunk/src/org


Ignore:
Timestamp:
2022-11-08T18:51:13+01:00 (2 years ago)
Author:
taylor.smock
Message:

Fix #22453: Decrease allocations/CPU samples in Geometry.getDistanceSegmentSegment

Statistics, using Mesa County, CO as the data ("nwr in 'Mesa County, CO'") with
the MapWithAI plugin validations enabled (validation run):

  • CPU samples: 54,604 -> 39,146 (-15,458, -28.3%)
  • Memory allocations: 170,983,028,400 -> 4,645,539,624 (-166,337,488,776, -97.3%)
    • All remaining allocations are from creating a new LatLon during interpolation.
  • .7% improvement in GC threads (overall, see notes).

Notes:

  • getDistanceWayNode was also modified to avoid EastNorth allocations.
  • All remaining allocations come from the creation of new LatLon objects. This may be alleviated when value classes become a thing in Java LTS, and we start using them.
  • Profiling was done from application startup to shut down.
Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/coor/ILatLon.java

    r18495 r18589  
    144144        return bearing;
    145145    }
     146
     147    /**
     148     * Does a linear interpolation between two ILatLon instances.
     149     * @param ll2 The other ILatLon instance.
     150     * @param proportion The proportion the other instance influences the result.
     151     * @return The new {@link ILatLon} position.
     152     * @since 18589
     153     */
     154    default ILatLon interpolate(ILatLon ll2, double proportion) {
     155        // this is an alternate form of this.lat() + proportion * (ll2.lat() - this.lat()) that is slightly faster
     156        return new LatLon((1 - proportion) * this.lat() + proportion * ll2.lat(),
     157                (1 - proportion) * this.lon() + proportion * ll2.lon());
     158    }
     159
     160    /**
     161     * Returns the square of euclidean distance from this {@code Coordinate} to a specified coordinate.
     162     *
     163     * @param lon the X coordinate of the specified point to be measured against this {@code Coordinate}
     164     * @param lat the Y coordinate of the specified point to be measured against this {@code Coordinate}
     165     * @return the square of the euclidean distance from this {@code Coordinate} to a specified coordinate
     166     * @since 18589
     167     */
     168    default double distanceSq(final double lon, final double lat) {
     169        final double dx = this.lon() - lon;
     170        final double dy = this.lat() - lat;
     171        return dx * dx + dy * dy;
     172    }
     173
     174    /**
     175     * Returns the euclidean distance from this {@code ILatLon} to a specified {@code ILatLon}.
     176     *
     177     * @param other the specified coordinate to be measured against this {@code ILatLon}
     178     * @return the euclidean distance from this {@code ILatLon} to a specified {@code ILatLon}
     179     * @since 18589
     180     */
     181    default double distanceSq(final ILatLon other) {
     182        return this.distanceSq(other.lon(), other.lat());
     183    }
    146184}
  • trunk/src/org/openstreetmap/josm/data/coor/LatLon.java

    r18495 r18589  
    259259
    260260    /**
    261      * Interpolate between this and a other latlon
     261     * Interpolate between this and a other latlon. If you don't care about the return type, use {@link ILatLon#interpolate(ILatLon, double)}
     262     * instead.
    262263     * @param ll2 The other lat/lon object
    263264     * @param proportion The proportion to interpolate
     
    265266     */
    266267    public LatLon interpolate(LatLon ll2, double proportion) {
    267         // this is an alternate form of this.lat() + proportion * (ll2.lat() - this.lat()) that is slightly faster
    268         return new LatLon((1 - proportion) * this.lat() + proportion * ll2.lat(),
    269                 (1 - proportion) * this.lon() + proportion * ll2.lon());
     268        ILatLon interpolated = ILatLon.super.interpolate(ll2, proportion);
     269        if (interpolated instanceof LatLon) {
     270            return (LatLon) interpolated;
     271        }
     272        return new LatLon(interpolated);
    270273    }
    271274
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r18553 r18589  
    492492        double pdx = point.getX() - p1.getX();
    493493        double pdy = point.getY() - p1.getY();
     494
     495        double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
     496
     497        if (segmentOnly && offset <= 0)
     498            return p1;
     499        else if (segmentOnly && offset >= 1)
     500            return p2;
     501        else
     502            return p1.interpolate(p2, offset);
     503    }
     504
     505    /**
     506     * Get the closest point to a segment
     507     * @param p1 Point 1 of the segment
     508     * @param p2 Point 2 of the segment
     509     * @param point The point to use to get the closest point on the segment
     510     * @param segmentOnly {@code true} if the point <i>must</i> be on the segment
     511     * @return The closest point on the segment if {@code segmentOnly = true}, otherwise the closest point on the infinite line.
     512     */
     513    private static ILatLon closestPointTo(ILatLon p1, ILatLon p2, ILatLon point, boolean segmentOnly) {
     514        CheckParameterUtil.ensureParameterNotNull(p1, "p1");
     515        CheckParameterUtil.ensureParameterNotNull(p2, "p2");
     516        CheckParameterUtil.ensureParameterNotNull(point, "point");
     517
     518        double ldx = p2.lon() - p1.lon();
     519        double ldy = p2.lat() - p1.lat();
     520
     521        //segment zero length
     522        if (ldx == 0 && ldy == 0)
     523            return p1;
     524
     525        double pdx = point.lon() - p1.lon();
     526        double pdy = point.lat() - p1.lat();
    494527
    495528        double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
     
    15011534
    15021535        double smallest = Double.MAX_VALUE;
    1503         EastNorth en0 = node.getEastNorth();
    15041536        // go through the nodes as if they were paired
    15051537        Iterator<Node> iter = way.getNodes().iterator();
    1506         EastNorth en1 = iter.next().getEastNorth();
     1538        Node en1 = iter.next();
    15071539        while (iter.hasNext()) {
    1508             EastNorth en2 = iter.next().getEastNorth();
    1509             double distance = getSegmentNodeDistSq(en1, en2, en0);
     1540            Node en2 = iter.next();
     1541            double distance = getSegmentNodeDistSq(en1, en2, node);
    15101542            if (distance < smallest)
    15111543                smallest = distance;
     
    15611593        Iterator<Node> iter1 = w1.getNodes().iterator();
    15621594        Node w1N1 = iter1.next();
     1595        List<Node> w2Nodes = w2.getNodes();
    15631596        while (iter1.hasNext()) {
    15641597            Node w1N2 = iter1.next();
    1565             Iterator<Node> iter2 = w2.getNodes().iterator();
     1598            Iterator<Node> iter2 = w2Nodes.iterator();
    15661599            Node w2N1 = iter2.next();
    15671600            while (iter2.hasNext()) {
     
    16021635     */
    16031636    public static double getDistanceSegmentSegment(Node ws1Node1, Node ws1Node2, Node ws2Node1, Node ws2Node2) {
    1604         EastNorth enWs1Node1 = ws1Node1.getEastNorth();
    1605         EastNorth enWs1Node2 = ws1Node2.getEastNorth();
    1606         EastNorth enWs2Node1 = ws2Node1.getEastNorth();
    1607         EastNorth enWs2Node2 = ws2Node2.getEastNorth();
    1608         if (enWs1Node1 == null || enWs1Node2 == null || enWs2Node1 == null || enWs2Node2 == null)
     1637        if (!ws1Node1.isLatLonKnown() || !ws1Node2.isLatLonKnown() || !ws2Node1.isLatLonKnown() || !ws2Node2.isLatLonKnown()) {
    16091638            return Double.NaN;
    1610         if (getSegmentSegmentIntersection(enWs1Node1, enWs1Node2, enWs2Node1, enWs2Node2) != null)
     1639        }
     1640        if (getSegmentSegmentIntersection(ws1Node1, ws1Node2, ws2Node1, ws2Node2) != null)
    16111641            return 0;
    16121642
    1613         double dist1sq = getSegmentNodeDistSq(enWs1Node1, enWs1Node2, enWs2Node1);
    1614         double dist2sq = getSegmentNodeDistSq(enWs1Node1, enWs1Node2, enWs2Node2);
    1615         double dist3sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node1);
    1616         double dist4sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node2);
     1643        double dist1sq = getSegmentNodeDistSq(ws1Node1, ws1Node2, ws2Node1);
     1644        double dist2sq = getSegmentNodeDistSq(ws1Node1, ws1Node2, ws2Node2);
     1645        double dist3sq = getSegmentNodeDistSq(ws2Node1, ws2Node2, ws1Node1);
     1646        double dist4sq = getSegmentNodeDistSq(ws2Node1, ws2Node2, ws1Node2);
    16171647        double smallest = Math.min(Math.min(dist1sq, dist2sq), Math.min(dist3sq, dist4sq));
    16181648        return smallest != Double.MAX_VALUE ? Math.sqrt(smallest) : Double.NaN;
     
    16491679     * @return the square of the euclidean distance from p to the closest point on the segment
    16501680     */
    1651     private static double getSegmentNodeDistSq(EastNorth s1, EastNorth s2, EastNorth p) {
    1652         EastNorth c1 = closestPointTo(s1, s2, p, true);
    1653         return c1.distanceSq(p);
     1681    private static double getSegmentNodeDistSq(ILatLon s1, ILatLon s2, ILatLon p) {
     1682        ILatLon c1 = closestPointTo(s1, s2, p, true);
     1683        return c1.distanceSq(p.lon(), p.lat());
    16541684    }
    16551685}
Note: See TracChangeset for help on using the changeset viewer.