Ticket #17388: GpxDistance_speed.patch

File GpxDistance_speed.patch, 4.6 KB (added by taylor.smock, 7 years ago)

Untested patch that adds a method to get the distance between the centroid of an OsmPrimitive and a Bounds, it also starts work on finding the closest Bounds.

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

     
    22package org.openstreetmap.josm.data.gpx;
    33
    44import java.util.ArrayList;
     5import java.util.Collection;
    56import java.util.List;
     7import java.util.TreeMap;
    68
     9import org.openstreetmap.josm.data.Bounds;
    710import org.openstreetmap.josm.data.coor.EastNorth;
    811import org.openstreetmap.josm.data.coor.LatLon;
    912import org.openstreetmap.josm.data.osm.Node;
     
    3033     * @return The shortest distance
    3134     */
    3235    public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) {
    33         return gpxData.getTrackPoints()
    34                 .mapToDouble(tp -> getDistance(p, tp))
    35                 .filter(x -> x >= 0)
    36                 .min().orElse(Double.MAX_VALUE);
     36        Collection<GpxTrack> tracks = gpxData.getTracks();
     37        TreeMap<GpxTrack, Double> trackDistances = new TreeMap<>();
     38        for (GpxTrack track : tracks) {
     39                Bounds bounds = track.getBounds();
     40                double distance = getMinDistanceBounds(p, bounds);
     41                trackDistances.put(track, distance);
     42
     43        }
     44        if (trackDistances.containsValue(0.0)) {
     45            double minDistance = Double.MAX_VALUE;
     46            for (GpxTrack track : trackDistances.keySet()) {
     47                if (trackDistances.get(track).equals(0.0)) {
     48                    for (GpxTrackSegment segment : track.getSegments()) {
     49                        for (WayPoint wp : segment.getWayPoints()) {
     50                            double distance = getDistance(p, wp);
     51                            if (distance < minDistance) minDistance = distance;
     52                        }
     53                    }
     54                }
     55            }
     56            return minDistance;
     57        } else {
     58            return gpxData.getTrackPoints()
     59                    .mapToDouble(tp -> getDistance(p, tp))
     60                    .filter(x -> x >= 0)
     61                    .min().orElse(Double.MAX_VALUE);
     62        }
    3763    }
    3864
    3965    /**
     
    145171        if (latlon == null || waypoint == null || waypoint.getCoor() == null) return Double.MAX_VALUE;
    146172        return waypoint.getCoor().greatCircleDistance(latlon);
    147173    }
     174
     175    /**
     176     * @param p OsmPrimitive to get the lowest distance to its centroid
     177     * @param bounds The bounds with which we are getting the distance to
     178     * @return The distance to the bounds (0 if the OsmPrimitive is inside the bounds)
     179     */
     180    public static double getMinDistanceBounds(OsmPrimitive p, Bounds bounds) {
     181        return getDistanceBounds(p, bounds, true);
     182    }
     183
     184    /**
     185     * @param p OsmPrimitive to get the furthest distance to its centroid
     186     * @param bounds The bounds with which we are getting the distance to
     187     * @return The furthest distance to the bounds
     188     */
     189    public static double getMaxDistanceBounds(OsmPrimitive p, Bounds bounds) {
     190        return getDistanceBounds(p, bounds, false);
     191    }
     192
     193    private static double getDistanceBounds(OsmPrimitive p, Bounds bounds, boolean closest) {
     194        // If the primitive is within the bounds, return 0
     195        if (bounds.toBBox().intersects(p.getBBox()) && closest) return 0;
     196
     197        // The order the corners are added is important! When connected in order, they _must_ form a rectangle.
     198        ArrayList<Node> corners = new ArrayList<>();
     199        corners.add(new Node(bounds.getMax()));
     200        corners.add(new Node(new LatLon(bounds.getMaxLat(), bounds.getMinLon())));
     201        corners.add(new Node(bounds.getMin()));
     202        corners.add(new Node(new LatLon(bounds.getMinLat(), bounds.getMaxLon())));
     203
     204        ArrayList<Way> ways = new ArrayList<>();
     205        for (int i = 0; i < corners.size(); i++) {
     206            ways.add(new Way());
     207            ways.get(i).addNode(corners.get(i));
     208            // Doing % corners.size() avoids requiring an if statement to avoid overflow (which _is_ expected)
     209            ways.get(i).addNode(corners.get((i + 1) % corners.size()));
     210        }
     211        double distance;
     212        if (closest) distance = Double.MAX_VALUE;
     213        else distance = Double.MIN_VALUE;
     214        for (Way way : ways) {
     215            // Not the best of ideas, but there isn't a method implemented for two ways
     216            double tdistance = getDistance(way, new WayPoint(p.getBBox().getCenter()));
     217            if ((closest && tdistance < distance) || (!closest && tdistance > distance)) {
     218                distance = tdistance;
     219            }
     220        }
     221        return distance;
     222    }
    148223}