Ticket #17616: 17616.patch

File 17616.patch, 16.4 KB (added by taylor.smock, 6 years ago)

Add functions to get distances between OsmPrimitives to Geometry.java, refactor GPXDistance.java to use the methods, and deprecate the methods used in GPXDIstance.java.

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

     
    3131     */
    3232    public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) {
    3333        return gpxData.getTrackPoints()
    34                 .mapToDouble(tp -> getDistance(p, tp))
     34                .mapToDouble(tp -> Geometry.getDistance(p, new Node(tp.getCoor())))
    3535                .filter(x -> x >= 0)
    3636                .min().orElse(Double.MAX_VALUE);
    3737    }
     
    4141     * @param p OsmPrimitive to get the distance to the WayPoint
    4242     * @param waypoint WayPoint to get the distance from
    4343     * @return The shortest distance between p and waypoint
     44     * @deprecated Use {@code Geometry.getDistance(p, new Node(waypoint.getCoor()))}
     45     * instead
    4446     */
     47    @Deprecated
    4548    public static double getDistance(OsmPrimitive p, WayPoint waypoint) {
    46         if (p instanceof Node) {
    47             return getDistanceNode((Node) p, waypoint);
    48         } else if (p instanceof Way) {
    49             return getDistanceWay((Way) p, waypoint);
    50         } else if (p instanceof Relation) {
    51             return getDistanceRelation((Relation) p, waypoint);
    52         }
    53         return Double.MAX_VALUE;
     49        return Geometry.getDistance(p, new Node(waypoint.getCoor()));
    5450    }
    5551
    5652    /**
     
    5854     * @param relation Relation to get the distance from
    5955     * @param waypoint WayPoint to get the distance to
    6056     * @return The distance between the relation and the waypoint
     57     * @deprecated Use {@code Geometry.getDistance(relation, new Node(waypoint.getCoor()))}
     58     * instead
    6159     */
     60    @Deprecated
    6261    public static double getDistanceRelation(Relation relation, WayPoint waypoint) {
    6362        double shortestDistance = Double.MAX_VALUE;
    6463        List<Node> nodes = new ArrayList<>(relation.getMemberPrimitives(Node.class));
     
    8584     * @param way Way to get the distance from
    8685     * @param waypoint WayPoint to get the distance to
    8786     * @return The distance between the way and the waypoint
     87     * @deprecated Use {@code Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor()))} instead
    8888     */
     89    @Deprecated
    8990    public static double getDistanceWay(Way way, WayPoint waypoint) {
    90         double shortestDistance = Double.MAX_VALUE;
    91         if (way == null || waypoint == null) return shortestDistance;
    92         LatLon llwaypoint = waypoint.getCoor();
    93         EastNorth enwaypoint = new EastNorth(llwaypoint.getY(), llwaypoint.getX());
    94         for (int i = 0; i < way.getNodesCount() - 1; i++) {
    95             double distance = Double.MAX_VALUE;
    96             LatLon llfirst = way.getNode(i).getCoor();
    97             LatLon llsecond = way.getNode(i + 1).getCoor();
    98             EastNorth first = new EastNorth(llfirst.getY(), llfirst.getX());
    99             EastNorth second = new EastNorth(llsecond.getY(), llsecond.getX());
    100             if (first.isValid() && second.isValid()) {
    101                 EastNorth closestPoint = Geometry.closestPointToSegment(first, second, enwaypoint);
    102                 distance = llwaypoint.greatCircleDistance(new LatLon(closestPoint.getX(), closestPoint.getY()));
    103             } else if (first.isValid() && !second.isValid()) {
    104                 distance = getDistanceEastNorth(first, waypoint);
    105             } else if (!first.isValid() && second.isValid()) {
    106                 distance = getDistanceEastNorth(second, waypoint);
    107             } else if (!first.isValid() && !second.isValid()) {
    108                 distance = Double.MAX_VALUE;
    109             }
    110             if (distance < shortestDistance) shortestDistance = distance;
    111 
    112         }
    113         return shortestDistance;
     91        return Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor()));
    11492    }
    11593
    11694    /**
     
    11896     * @param node Node to get the distance from
    11997     * @param waypoint WayPoint to get the distance to
    12098     * @return The distance between the two points
     99     * @deprecated Use {@code Geometry.getDistance(node, new Node(waypoint.getCoor()))}
     100     * instead
    121101     */
     102    @Deprecated
    122103    public static double getDistanceNode(Node node, WayPoint waypoint) {
    123         if (node == null) return Double.MAX_VALUE;
    124         return getDistanceLatLon(node.getCoor(), waypoint);
     104        return Geometry.getDistance(node, new Node(waypoint.getCoor()));
    125105    }
    126106
    127107    /**
     
    129109     * @param en The EastNorth to get the distance to
    130110     * @param waypoint WayPoint to get the distance to
    131111     * @return The distance between the two points
     112     * @deprecated Use {@code Geometry.getDistance(new Node(en), new Node(waypoint.getCoor()))} instead
    132113     */
     114    @Deprecated
    133115    public static double getDistanceEastNorth(EastNorth en, WayPoint waypoint) {
    134         if (en == null || !en.isValid()) return Double.MAX_VALUE;
    135         return getDistanceLatLon(new LatLon(en.getY(), en.getX()), waypoint);
     116        return Geometry.getDistance(new Node(en), new Node(waypoint.getCoor()));
    136117    }
    137118
    138119    /**
     
    140121     * @param latlon LatLon to get the distance from
    141122     * @param waypoint WayPoint to get the distance to
    142123     * @return The distance between the two points
     124     * @deprecated Use {@code Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor()))} instead
    143125     */
     126    @Deprecated
    144127    public static double getDistanceLatLon(LatLon latlon, WayPoint waypoint) {
    145128        if (latlon == null || waypoint == null || waypoint.getCoor() == null) return Double.MAX_VALUE;
    146         return waypoint.getCoor().greatCircleDistance(latlon);
     129        return Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor()));
    147130    }
    148131}
  • src/org/openstreetmap/josm/tools/Geometry.java

     
    88import java.math.BigDecimal;
    99import java.math.MathContext;
    1010import java.util.ArrayList;
     11import java.util.Collection;
    1112import java.util.Collections;
    1213import java.util.Comparator;
    1314import java.util.EnumSet;
     
    3031import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon;
    3132import org.openstreetmap.josm.data.osm.Node;
    3233import org.openstreetmap.josm.data.osm.NodePositionComparator;
     34import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3335import org.openstreetmap.josm.data.osm.Relation;
    3436import org.openstreetmap.josm.data.osm.Way;
     37import org.openstreetmap.josm.data.osm.WaySegment;
    3538import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    3639import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
    3740import org.openstreetmap.josm.data.projection.Projection;
     
    10701073        }
    10711074        return new AreaAndPerimeter(Math.abs(area) / 2, perimeter);
    10721075    }
     1076
     1077    /**
     1078     * Get the closest primitive to {@code osm} from the collection of OsmPrimitive {@code primitives}
     1079     * @param osm The primitive to get the distances from
     1080     * @param primitives The collection of primitives to get the distance to
     1081     * @return The closest {@code OsmPrimitive}
     1082     * @since xxx
     1083     */
     1084    public static OsmPrimitive getClosestPrimitive(OsmPrimitive osm, Collection<OsmPrimitive> primitives) {
     1085        double lowestDistance = Double.MAX_VALUE;
     1086        OsmPrimitive closest = null;
     1087        for (OsmPrimitive primitive : primitives) {
     1088            double distance = getDistance(osm, primitive);
     1089            if (distance < lowestDistance) {
     1090                lowestDistance = distance;
     1091                closest = primitive;
     1092            }
     1093        }
     1094        return closest;
     1095    }
     1096
     1097    /**
     1098     * Get the furthest primitive to {@code osm} from the collection of OsmPrimitive {@code primitives}
     1099     * @param osm The primitive to get the distances from
     1100     * @param primitives The collection of primitives to get the distance to
     1101     * @return The furthest {@code OsmPrimitive}
     1102     * @since xxx
     1103     */
     1104    public static OsmPrimitive getFurthestPrimitive(OsmPrimitive osm, Collection<OsmPrimitive> primitives) {
     1105        double furthestDistance = Double.MIN_VALUE;
     1106        OsmPrimitive furthest = null;
     1107        for (OsmPrimitive primitive : primitives) {
     1108            double distance = getDistance(osm, primitive);
     1109            if (distance > furthestDistance) {
     1110                distance = furthestDistance;
     1111                furthest = primitive;
     1112            }
     1113        }
     1114        return furthest;
     1115    }
     1116
     1117    /**
     1118     * Get the distance between different {@code OsmPrimitive}s
     1119     * @param one The primitive to get the distance from
     1120     * @param two The primitive to get the distance to
     1121     * @return The distance between the primitives
     1122     * @since xxx
     1123     */
     1124    public static double getDistance(OsmPrimitive one, OsmPrimitive two) {
     1125        double rValue = Double.MAX_VALUE;
     1126        if (one == null || two == null) return rValue;
     1127        if (one instanceof Node && two instanceof Node) {
     1128            rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());
     1129        } else if (one instanceof Node && two instanceof Way) {
     1130            rValue = getDistanceWayNode((Way) two, (Node) one);
     1131        } else if (one instanceof Way && two instanceof Node) {
     1132            rValue = getDistanceWayNode((Way) one, (Node) two);
     1133        } else if (one instanceof Way && two instanceof Way) {
     1134            rValue = getDistanceWayWay((Way) one, (Way) two);
     1135        } else if (one instanceof Relation && !(two instanceof Relation)) {
     1136            for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) {
     1137                double currentDistance = getDistance(osmPrimitive, two);
     1138                if (currentDistance < rValue) rValue = currentDistance;
     1139            }
     1140        } else if (!(one instanceof Relation) && two instanceof Relation) {
     1141            for (OsmPrimitive osmPrimitive : ((Relation) two).getMemberPrimitives()) {
     1142                double currentDistance = getDistance(osmPrimitive, one);
     1143                if (currentDistance < rValue) rValue = currentDistance;
     1144            }
     1145        }
     1146        return rValue;
     1147    }
     1148
     1149    /**
     1150     * Get the distance between a way and a node
     1151     * @param way The way to get the distance from
     1152     * @param node The node to get the distance to
     1153     * @return The distance between the {@code way} and the {@code node}
     1154     * @since xxx
     1155     */
     1156    public static double getDistanceWayNode(Way way, Node node) {
     1157        double rValue = Double.MAX_VALUE;
     1158        if (way.getNodesCount() < 2) return rValue;
     1159        List<WaySegment> segments = getWaySegments(way);
     1160        for (WaySegment segment : segments) {
     1161            EastNorth point = Geometry.closestPointToSegment(segment.getFirstNode().getEastNorth(), segment.getSecondNode().getEastNorth(), node.getEastNorth());
     1162            double distance = point.distance(node.getEastNorth());
     1163            if (distance < rValue) rValue = distance;
     1164        }
     1165        return rValue;
     1166    }
     1167
     1168    /**
     1169     * Get the closest {@code WaySegment} from a way to a primitive
     1170     * @param way The {@code Way} to get the distance from and the {@code WaySegment}
     1171     * @param primitive The {@code Primitive} to get the distance to
     1172     * @return The {@code WaySegment} that is closest to {@code primitive} from {@code way}
     1173     * @since xxx
     1174     */
     1175    public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) {
     1176        List<WaySegment> segments = getWaySegments(way);
     1177        double lowestDistance = Double.MAX_VALUE;
     1178        WaySegment closest = null;
     1179        for (WaySegment segment : segments) {
     1180            double distance = getDistance(segment.toWay(), primitive);
     1181            if (distance < lowestDistance) {
     1182                lowestDistance = distance;
     1183                closest = segment;
     1184            }
     1185        }
     1186        return closest;
     1187    }
     1188
     1189    /**
     1190     * Get the distance between different ways
     1191     * @param one The way to get the distance from
     1192     * @param two The {@code Way} to get the distance to
     1193     * @return The shortest distance between the ways
     1194     * @since xxx
     1195     */
     1196    public static double getDistanceWayWay(Way one, Way two) {
     1197        double rValue = Double.MAX_VALUE;
     1198        List<WaySegment> oneSegments = getWaySegments(one);
     1199        List<WaySegment> twoSegments = getWaySegments(two);
     1200        for (WaySegment oneSegment : oneSegments) {
     1201            for (WaySegment twoSegment : twoSegments) {
     1202                EastNorth en1 = oneSegment.getFirstNode().getEastNorth();
     1203                EastNorth en2 = oneSegment.getSecondNode().getEastNorth();
     1204                EastNorth en3 = twoSegment.getFirstNode().getEastNorth();
     1205                EastNorth en4 = twoSegment.getSecondNode().getEastNorth();
     1206                if (en1 == null || en2 == null || en3 == null || en4 == null) continue;
     1207                EastNorth intersection = Geometry.getSegmentSegmentIntersection(
     1208                        en1, en2, en3, en4);
     1209                if (intersection != null) return 0.0;
     1210                double distance = getDistanceSegmentSegment(oneSegment, twoSegment);
     1211                if (distance < rValue) rValue = distance;
     1212            }
     1213        }
     1214        return rValue;
     1215    }
     1216
     1217    /**
     1218     * Get the distance between different {@code WaySegment}s
     1219     * @param one A {@code WaySegment} to get the distance from
     1220     * @param two A {@code WaySegment} to get the distance to
     1221     * @return The distance between the two {@code WaySegment}s
     1222     * @since xxx
     1223     */
     1224    public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) {
     1225        EastNorth vectorOne = one.getSecondNode().getEastNorth().subtract(one.getFirstNode().getEastNorth());
     1226        EastNorth vectorTwo = two.getSecondNode().getEastNorth().subtract(two.getFirstNode().getEastNorth());
     1227        EastNorth vectorThree = one.getFirstNode().getEastNorth().subtract(two.getFirstNode().getEastNorth());
     1228        double smallNumber = 0.00000000001;
     1229        double a = dot(vectorOne, vectorOne);
     1230        double b = dot(vectorOne, vectorTwo);
     1231        double c = dot(vectorTwo, vectorTwo);
     1232        double d = dot(vectorOne, vectorThree);
     1233        double e = dot(vectorTwo, vectorThree);
     1234
     1235        double D = a * c - b * b;
     1236        double sc, sN, sD = d;
     1237        double tc, tN, tD = D;
     1238        if (D < smallNumber) {
     1239            sN = 0.0;
     1240            sD = 1.0;
     1241            tN = e;
     1242            tD = c;
     1243        } else {
     1244            sN = (b * e - c * d);
     1245            tN = (a * e - b * d);
     1246            if (sN < 0.0) {
     1247                sN = 0.0;
     1248                tN = e;
     1249                tD = c;
     1250            } else if (sN > sD) {
     1251                sN = sD;
     1252                tN = e + b;
     1253                tD = c;
     1254            }
     1255        }
     1256
     1257        if (tN < 0.0) {
     1258            tN = 0.0;
     1259            if (-d < 0.0) sN = 0.0;
     1260            else if (-d > a) sN = sD;
     1261            else {
     1262                sN = -d;
     1263                sD = a;
     1264            }
     1265        } else if (tN > tD) {
     1266            tN = tD;
     1267            if ((-d + b) < 0.0) sN = 0;
     1268            else if ((-d + b) > a) sN = sD;
     1269            else {
     1270                sN = (-d + b);
     1271                sD = a;
     1272            }
     1273        }
     1274        sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD;
     1275        tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD;
     1276        EastNorth p1 = one.getFirstNode().getEastNorth().interpolate(one.getSecondNode().getEastNorth(), sc);
     1277        EastNorth p2 = two.getFirstNode().getEastNorth().interpolate(two.getSecondNode().getEastNorth(), tc);
     1278        return p1.distance(p2);
     1279    }
     1280
     1281    /**
     1282     * Get the dot product of two different EastNorth points
     1283     * @param one The originating EastNorth
     1284     * @param two The final EastNorth
     1285     * @return the dot product of the EastNorths
     1286     * @since xxx
     1287     */
     1288    public static double dot(EastNorth one, EastNorth two) {
     1289        return two.getX() * one.getX() + one.getY() * two.getY();
     1290    }
     1291
     1292    /**
     1293     * Get the way segments of a way
     1294     * @param way The way to get the way segments of
     1295     * @return A lest of {@code WaySegment}s
     1296     * @since xxx
     1297     */
     1298    public static List<WaySegment> getWaySegments(Way way) {
     1299        List<WaySegment> segments = new ArrayList<>();
     1300        int i = 0;
     1301        do {
     1302            segments.add(new WaySegment(way, i));
     1303            i++;
     1304        } while (i < way.getNodesCount() - 2);
     1305        return segments;
     1306    }
    10731307}