| | 48 | * Get tracks that are relevant to an OsmPrimitive |
| | 49 | * @param p OsmPrimitive that we need relevant tracks for |
| | 50 | * @param gpxData Data that has the tracks |
| | 51 | * @return {@code HashSet} of GpxTracks that include the primitive (or are |
| | 52 | * the closest) or overlap with the the closest tracks. |
| | 53 | * |
| | 54 | * @since xxx |
| | 55 | */ |
| | 56 | public static GpxData getRelevantData(OsmPrimitive p, GpxData gpxData) { |
| | 57 | HashSet<GpxTrack> relevantTracks = new HashSet<>(); |
| | 58 | Collection<GpxTrack> tracks = gpxData.getTracks(); |
| | 59 | HashMap<GpxTrack, Double> trackDistances = new HashMap<>(); |
| | 60 | for (GpxTrack track : tracks) { |
| | 61 | Bounds bounds = track.getBounds(); |
| | 62 | double distance = getMinDistanceBounds(p, bounds); |
| | 63 | trackDistances.put(track, distance); |
| | 64 | } |
| | 65 | Iterator<GpxTrack> trackIterator = trackDistances.keySet().iterator(); |
| | 66 | double minValue = trackDistances.values().stream().min(Double::compare).get(); |
| | 67 | double furthestDistance = Double.MIN_VALUE; |
| | 68 | while (trackIterator.hasNext()) { |
| | 69 | GpxTrack track = trackIterator.next(); |
| | 70 | if (trackDistances.getOrDefault(trackDistances, Double.MAX_VALUE).compareTo(minValue) == 0) { |
| | 71 | relevantTracks.add(track); |
| | 72 | double mdistance = getMaxDistanceBounds(p, track.getBounds()); |
| | 73 | if (mdistance > furthestDistance) furthestDistance = mdistance; |
| | 74 | } |
| | 75 | } |
| | 76 | trackDistances.entrySet().removeIf((track) -> relevantTracks.contains(track)); |
| | 77 | trackIterator = trackDistances.keySet().iterator(); |
| | 78 | while (trackIterator.hasNext()) { |
| | 79 | GpxTrack track = trackIterator.next(); |
| | 80 | double mdistance = getMinDistanceBounds(p, track.getBounds()); |
| | 81 | if (mdistance < furthestDistance) { |
| | 82 | relevantTracks.add(track); |
| | 83 | } |
| | 84 | } |
| | 85 | GpxData rData = new GpxData(); |
| | 86 | relevantTracks.forEach(track -> rData.addTrack(track)); |
| | 87 | return rData; |
| | 88 | } |
| | 89 | |
| | 90 | /** |
| | 199 | |
| | 200 | /** |
| | 201 | * @param p OsmPrimitive to get the lowest distance to its centroid |
| | 202 | * @param bounds The bounds with which we are getting the distance to |
| | 203 | * @return The distance to the bounds (0 if the OsmPrimitive is inside the bounds) |
| | 204 | */ |
| | 205 | public static double getMinDistanceBounds(OsmPrimitive p, Bounds bounds) { |
| | 206 | return getDistanceBounds(p, bounds, true); |
| | 207 | } |
| | 208 | |
| | 209 | /** |
| | 210 | * @param p OsmPrimitive to get the furthest distance to its centroid |
| | 211 | * @param bounds The bounds with which we are getting the distance to |
| | 212 | * @return The furthest distance to the bounds |
| | 213 | */ |
| | 214 | public static double getMaxDistanceBounds(OsmPrimitive p, Bounds bounds) { |
| | 215 | return getDistanceBounds(p, bounds, false); |
| | 216 | } |
| | 217 | |
| | 218 | private static double getDistanceBounds(OsmPrimitive p, Bounds bounds, boolean closest) { |
| | 219 | // If the primitive is within the bounds, return 0 |
| | 220 | if (bounds.toBBox().intersects(p.getBBox()) && closest) return 0; |
| | 221 | |
| | 222 | // The order the corners are added is important! When connected in order, they _must_ form a rectangle. |
| | 223 | ArrayList<Node> corners = new ArrayList<>(); |
| | 224 | corners.add(new Node(bounds.getMax())); |
| | 225 | corners.add(new Node(new LatLon(bounds.getMaxLat(), bounds.getMinLon()))); |
| | 226 | corners.add(new Node(bounds.getMin())); |
| | 227 | corners.add(new Node(new LatLon(bounds.getMinLat(), bounds.getMaxLon()))); |
| | 228 | |
| | 229 | ArrayList<Way> ways = new ArrayList<>(); |
| | 230 | for (int i = 0; i < corners.size(); i++) { |
| | 231 | ways.add(new Way()); |
| | 232 | ways.get(i).addNode(corners.get(i)); |
| | 233 | // Doing % corners.size() avoids requiring an if statement to avoid overflow (which _is_ expected) |
| | 234 | ways.get(i).addNode(corners.get((i + 1) % corners.size())); |
| | 235 | } |
| | 236 | double distance; |
| | 237 | if (closest) distance = Double.MAX_VALUE; |
| | 238 | else distance = Double.MIN_VALUE; |
| | 239 | for (Way way : ways) { |
| | 240 | // Not the best of ideas, but there isn't a method implemented for two ways |
| | 241 | double tdistance = getDistance(way, new WayPoint(p.getBBox().getCenter())); |
| | 242 | if ((closest && tdistance < distance) || (!closest && tdistance > distance)) { |
| | 243 | distance = tdistance; |
| | 244 | } |
| | 245 | } |
| | 246 | return distance; |
| | 247 | } |