Index: src/org/openstreetmap/josm/data/gpx/GpxDistance.java
===================================================================
--- src/org/openstreetmap/josm/data/gpx/GpxDistance.java	(revision 14819)
+++ src/org/openstreetmap/josm/data/gpx/GpxDistance.java	(working copy)
@@ -2,8 +2,13 @@
 package org.openstreetmap.josm.data.gpx;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
@@ -30,6 +35,9 @@
      * @return The shortest distance
      */
     public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) {
+        if (gpxData.getTrackCount() > 1) {
+            gpxData = getRelevantData(p, gpxData);
+        }
         return gpxData.getTrackPoints()
                 .mapToDouble(tp -> getDistance(p, tp))
                 .filter(x -> x >= 0)
@@ -37,6 +45,49 @@
     }
 
     /**
+     * Get tracks that are relevant to an OsmPrimitive
+     * @param p OsmPrimitive that we need relevant tracks for
+     * @param gpxData Data that has the tracks
+     * @return {@code HashSet} of GpxTracks that include the primitive (or are
+     * the closest) or overlap with the the closest tracks.
+     *
+     * @since xxx
+     */
+    public static GpxData getRelevantData(OsmPrimitive p, GpxData gpxData) {
+        HashSet<GpxTrack> relevantTracks = new HashSet<>();
+        Collection<GpxTrack> tracks = gpxData.getTracks();
+        HashMap<GpxTrack, Double> trackDistances = new HashMap<>();
+        for (GpxTrack track : tracks) {
+            Bounds bounds = track.getBounds();
+            double distance = getMinDistanceBounds(p, bounds);
+            trackDistances.put(track, distance);
+        }
+        Iterator<GpxTrack> trackIterator = trackDistances.keySet().iterator();
+        double minValue = trackDistances.values().stream().min(Double::compare).get();
+        double furthestDistance = Double.MIN_VALUE;
+        while (trackIterator.hasNext()) {
+            GpxTrack track = trackIterator.next();
+            if (trackDistances.getOrDefault(trackDistances, Double.MAX_VALUE).compareTo(minValue) == 0) {
+                relevantTracks.add(track);
+                double mdistance = getMaxDistanceBounds(p, track.getBounds());
+                if (mdistance > furthestDistance) furthestDistance = mdistance;
+            }
+        }
+        trackDistances.entrySet().removeIf((track) -> relevantTracks.contains(track));
+        trackIterator = trackDistances.keySet().iterator();
+        while (trackIterator.hasNext()) {
+            GpxTrack track = trackIterator.next();
+            double mdistance = getMinDistanceBounds(p, track.getBounds());
+            if (mdistance < furthestDistance) {
+                relevantTracks.add(track);
+            }
+        }
+        GpxData rData = new GpxData();
+        relevantTracks.forEach(track -> rData.addTrack(track));
+        return rData;
+    }
+
+    /**
      * Get the distance between an object and a waypoint
      * @param p OsmPrimitive to get the distance to the WayPoint
      * @param waypoint WayPoint to get the distance from
@@ -145,4 +196,53 @@
         if (latlon == null || waypoint == null || waypoint.getCoor() == null) return Double.MAX_VALUE;
         return waypoint.getCoor().greatCircleDistance(latlon);
     }
+
+    /**
+     * @param p OsmPrimitive to get the lowest distance to its centroid
+     * @param bounds The bounds with which we are getting the distance to
+     * @return The distance to the bounds (0 if the OsmPrimitive is inside the bounds)
+     */
+    public static double getMinDistanceBounds(OsmPrimitive p, Bounds bounds) {
+        return getDistanceBounds(p, bounds, true);
+    }
+
+    /**
+     * @param p OsmPrimitive to get the furthest distance to its centroid
+     * @param bounds The bounds with which we are getting the distance to
+     * @return The furthest distance to the bounds
+     */
+    public static double getMaxDistanceBounds(OsmPrimitive p, Bounds bounds) {
+        return getDistanceBounds(p, bounds, false);
+    }
+
+    private static double getDistanceBounds(OsmPrimitive p, Bounds bounds, boolean closest) {
+        // If the primitive is within the bounds, return 0
+        if (bounds.toBBox().intersects(p.getBBox()) && closest) return 0;
+
+        // The order the corners are added is important! When connected in order, they _must_ form a rectangle.
+        ArrayList<Node> corners = new ArrayList<>();
+        corners.add(new Node(bounds.getMax()));
+        corners.add(new Node(new LatLon(bounds.getMaxLat(), bounds.getMinLon())));
+        corners.add(new Node(bounds.getMin()));
+        corners.add(new Node(new LatLon(bounds.getMinLat(), bounds.getMaxLon())));
+
+        ArrayList<Way> ways = new ArrayList<>();
+        for (int i = 0; i < corners.size(); i++) {
+            ways.add(new Way());
+            ways.get(i).addNode(corners.get(i));
+            // Doing % corners.size() avoids requiring an if statement to avoid overflow (which _is_ expected)
+            ways.get(i).addNode(corners.get((i + 1) % corners.size()));
+        }
+        double distance;
+        if (closest) distance = Double.MAX_VALUE;
+        else distance = Double.MIN_VALUE;
+        for (Way way : ways) {
+            // Not the best of ideas, but there isn't a method implemented for two ways
+            double tdistance = getDistance(way, new WayPoint(p.getBBox().getCenter()));
+            if ((closest && tdistance < distance) || (!closest && tdistance > distance)) {
+                distance = tdistance;
+            }
+        }
+        return distance;
+    }
 }
