Ticket #17131: gpx_distance_v4.patch

File gpx_distance_v4.patch, 9.7 KB (added by taylor.smock, 7 years ago)

Now uses Geometry.closestPointToSegment for getting the shortest distance from a point to a way.

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

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.gpx;
     3
     4import java.util.ArrayList;
     5import java.util.List;
     6import java.util.stream.Collectors;
     7
     8import org.openstreetmap.josm.data.coor.EastNorth;
     9import org.openstreetmap.josm.data.coor.LatLon;
     10import org.openstreetmap.josm.data.osm.Node;
     11import org.openstreetmap.josm.data.osm.OsmPrimitive;
     12import org.openstreetmap.josm.data.osm.Relation;
     13import org.openstreetmap.josm.data.osm.Way;
     14import org.openstreetmap.josm.gui.MainApplication;
     15import org.openstreetmap.josm.gui.layer.GpxLayer;
     16import org.openstreetmap.josm.gui.layer.Layer;
     17import org.openstreetmap.josm.gui.layer.LayerManager;
     18import org.openstreetmap.josm.tools.Geometry;
     19
     20/**
     21 * A class to find the distance between an OsmPrimitive and a GPX point
     22 *
     23 * @author Taylor Smock
     24 *
     25 */
     26public final class GpxDistance {
     27    private GpxDistance() {
     28        // This class should not be instantiated
     29    }
     30
     31    /**
     32     * @param p The OsmPrimitive that we are checking the maximum distance for
     33     * @param maximumDistance The maximum distance from a GPX point to the OsmPrimitive
     34     * @return true if the distance to the closest GPX point is lower than maximumDistance
     35     */
     36    public static boolean isCloseTo(OsmPrimitive p, double maximumDistance) {
     37        double distance = getLowestDistance(p);
     38        return (distance < maximumDistance);
     39    }
     40
     41    /**
     42     * Get the lowest distance from the layers to p
     43     * @param p OsmPrimitive from which to get the lowest distance to a GPX point
     44     * @return the lowest distance from any GpxLayer to p.
     45     */
     46    public static double getLowestDistance(OsmPrimitive p) {
     47        LayerManager layerManager = MainApplication.getLayerManager();
     48        List<Layer> layers = layerManager.getLayers();
     49        double distance = Double.MAX_VALUE;
     50        for (Layer layer : layers) {
     51            double tdistance = getLowestDistance(p, layer);
     52            if (tdistance < distance) distance = tdistance;
     53        }
     54        return distance;
     55    }
     56
     57    /**
     58     * Find the distance between a point and a layer of surveyed points
     59     * @param p OsmPrimitive from which to get the lowest distance to a GPX point
     60     * @param layer Layer from which to get the GPX points (currently, only GpxLayer is supported)
     61     * @return The shortest distance
     62     */
     63    public static double getLowestDistance(OsmPrimitive p, Layer layer) {
     64        if (layer instanceof GpxLayer) {
     65            GpxLayer gpxLayer = (GpxLayer) layer;
     66            GpxData gpxData = gpxLayer.data;
     67            List<WayPoint> trackPoints = gpxData.getTrackPoints().collect(Collectors.toList());
     68            double lowestDistance = Double.MAX_VALUE;
     69            for (WayPoint trackPoint : trackPoints) {
     70                double distance = getDistance(p, trackPoint);
     71                if (distance >= 0.0 && distance < lowestDistance) lowestDistance = distance;
     72            }
     73            return lowestDistance;
     74        }
     75        return Double.MAX_VALUE;
     76    }
     77
     78    /**
     79     * Get the distance between an object and a waypoint
     80     * @param p OsmPrimitive to get the distance to the WayPoint
     81     * @param waypoint WayPoint to get the distance from
     82     * @return The shortest distance between p and waypoint
     83     */
     84    public static double getDistance(OsmPrimitive p, WayPoint waypoint) {
     85        if (p instanceof Node) {
     86            return getDistanceNode((Node) p, waypoint);
     87        } else if (p instanceof Way) {
     88            return getDistanceWay((Way) p, waypoint);
     89        } else if (p instanceof Relation) {
     90            return getDistanceRelation((Relation) p, waypoint);
     91        }
     92        return Double.MAX_VALUE;
     93    }
     94
     95    /**
     96     * Get the shortest distance between a relation and a waypoint
     97     * @param relation Relation to get the distance from
     98     * @param waypoint WayPoint to get the distance to
     99     * @return The distance between the relation and the waypoint
     100     */
     101    public static double getDistanceRelation(Relation relation, WayPoint waypoint) {
     102        double shortestDistance = Double.MAX_VALUE;
     103        List<Node> nodes = new ArrayList<>(relation.getMemberPrimitives(Node.class));
     104        List<Way> ways = new ArrayList<>(relation.getMemberPrimitives(Way.class));
     105        List<Relation> relations = new ArrayList<>(relation.getMemberPrimitives(Relation.class));
     106        if (nodes.isEmpty() && ways.isEmpty() && relations.isEmpty()) return Double.MAX_VALUE;
     107        for (Relation nrelation : relations) {
     108            double distance = getDistanceRelation(nrelation, waypoint);
     109            if (distance < shortestDistance) shortestDistance = distance;
     110        }
     111        for (Way way : ways) {
     112            double distance = getDistanceWay(way, waypoint);
     113            if (distance < shortestDistance) shortestDistance = distance;
     114        }
     115        for (Node node : nodes) {
     116            double distance = getDistanceNode(node, waypoint);
     117            if (distance < shortestDistance) shortestDistance = distance;
     118        }
     119        return shortestDistance;
     120    }
     121
     122    /**
     123     * Get the shortest distance between a way and a waypoint
     124     * @param way Way to get the distance from
     125     * @param waypoint WayPoint to get the distance to
     126     * @return The distance between the way and the waypoint
     127     */
     128    public static double getDistanceWay(Way way, WayPoint waypoint) {
     129        double shortestDistance = Double.MAX_VALUE;
     130        EastNorth enwaypoint = new EastNorth(waypoint.getCoor().getX(),
     131                waypoint.getCoor().getY());
     132        for (int i = 0; i < way.getNodesCount() - 1; i++) {
     133            double distance = Double.MAX_VALUE;
     134            EastNorth first = new EastNorth(way.getNode(i).getCoor().getX(),
     135                    way.getNode(i).getCoor().getY());
     136            EastNorth second = new EastNorth(way.getNode(i+1).getCoor().getX(),
     137                    way.getNode(i+1).getCoor().getY());
     138            if (first.isValid() && second.isValid()) {
     139                EastNorth closestPoint = Geometry.closestPointToSegment(first, second, enwaypoint);
     140                distance = closestPoint.distance(waypoint.getCoor().getX(), waypoint.getCoor().getY());
     141            } else if (first.isValid() && !second.isValid()) {
     142                distance = getDistanceEastNorth(first, waypoint);
     143            } else if (!first.isValid() && second.isValid()) {
     144                distance = getDistanceEastNorth(second, waypoint);
     145            } else if (!first.isValid() && !second.isValid()) {
     146                distance = Double.MAX_VALUE;
     147            }
     148            if (distance < shortestDistance) shortestDistance = distance;
     149
     150        }
     151        return shortestDistance;
     152    }
     153
     154    /**
     155     * Get the distance between a node and a waypoint
     156     * @param node Node to get the distance from
     157     * @param waypoint WayPoint to get the distance to
     158     * @return The distance between the two points
     159     */
     160    public static double getDistanceNode(Node node, WayPoint waypoint) {
     161        return getDistanceLatLon(node.getCoor(), waypoint);
     162    }
     163
     164    /**
     165     * Get the distance between coordinates (provided by EastNorth) and a waypoint
     166     * @param en The EastNorth to get the distance to
     167     * @param waypoint WayPoint to get the distance to
     168     * @return The distance between the two points
     169     */
     170    public static double getDistanceEastNorth(EastNorth en, WayPoint waypoint) {
     171        if (!en.isValid() || waypoint.getCoor() == null) return Double.MAX_VALUE;
     172        return getDistanceLatLon(new LatLon(en.getY(), en.getX()), waypoint);
     173    }
     174
     175    /**
     176     * Get the distance between coordinates (latitude longitude) and a waypoint
     177     * @param latlon LatLon to get the distance from
     178     * @param waypoint WayPoint to get the distance to
     179     * @return The distance between the two points
     180     */
     181    public static double getDistanceLatLon(LatLon latlon, WayPoint waypoint) {
     182        if (latlon == null || waypoint.getCoor() == null) return Double.MAX_VALUE;
     183        return waypoint.getCoor().greatCircleDistance(latlon);
     184    }
     185}
  • src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java

     
    2424import java.util.zip.CRC32;
    2525
    2626import org.openstreetmap.josm.data.coor.LatLon;
     27import org.openstreetmap.josm.data.gpx.GpxDistance;
    2728import org.openstreetmap.josm.data.osm.IPrimitive;
    2829import org.openstreetmap.josm.data.osm.Node;
     30import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2931import org.openstreetmap.josm.data.osm.Way;
    3032import org.openstreetmap.josm.data.osm.search.SearchCompiler;
    3133import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
     
    519521        }
    520522
    521523        /**
     524         * Returns the lowest distance between the OSM object and a GPX point
     525         * <p>
     526         * @param env the environment
     527         * @return the distance between the object and the closest gpx point or {@code Double.MAX_VALUE}
     528         */
     529        public static double gpx_distance(final Environment env) { // NO_UCD (unused code)
     530            if (env.osm instanceof OsmPrimitive) {
     531                return GpxDistance.getLowestDistance((OsmPrimitive) env.osm);
     532            } else {
     533                return Double.MAX_VALUE;
     534            }
     535        }
     536
     537        /**
    522538         * Determines whether the object has a tag with the given key.
    523539         * @param env the environment
    524540         * @param key the OSM key