Ticket #17616: 17616.2.patch
File 17616.2.patch, 22.5 KB (added by , 6 years ago) |
---|
-
src/org/openstreetmap/josm/data/gpx/GpxDistance.java
31 31 */ 32 32 public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) { 33 33 return gpxData.getTrackPoints() 34 .mapToDouble(tp -> getDistance(p, tp))34 .mapToDouble(tp -> Geometry.getDistance(p, new Node(tp.getCoor()))) 35 35 .filter(x -> x >= 0) 36 36 .min().orElse(Double.MAX_VALUE); 37 37 } … … 41 41 * @param p OsmPrimitive to get the distance to the WayPoint 42 42 * @param waypoint WayPoint to get the distance from 43 43 * @return The shortest distance between p and waypoint 44 * @deprecated Use {@code Geometry.getDistance(p, new Node(waypoint.getCoor()))} 45 * instead 44 46 */ 47 @Deprecated 45 48 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())); 54 50 } 55 51 56 52 /** … … 58 54 * @param relation Relation to get the distance from 59 55 * @param waypoint WayPoint to get the distance to 60 56 * @return The distance between the relation and the waypoint 57 * @deprecated Use {@code Geometry.getDistance(relation, new Node(waypoint.getCoor()))} 58 * instead 61 59 */ 60 @Deprecated 62 61 public static double getDistanceRelation(Relation relation, WayPoint waypoint) { 63 62 double shortestDistance = Double.MAX_VALUE; 64 63 List<Node> nodes = new ArrayList<>(relation.getMemberPrimitives(Node.class)); … … 85 84 * @param way Way to get the distance from 86 85 * @param waypoint WayPoint to get the distance to 87 86 * @return The distance between the way and the waypoint 87 * @deprecated Use {@code Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor()))} instead 88 88 */ 89 @Deprecated 89 90 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 if (way == null || waypoint == null) return Double.MAX_VALUE; 92 return Geometry.getDistanceWayNode(way, new Node(waypoint.getCoor())); 114 93 } 115 94 116 95 /** … … 118 97 * @param node Node to get the distance from 119 98 * @param waypoint WayPoint to get the distance to 120 99 * @return The distance between the two points 100 * @deprecated Use {@code Geometry.getDistance(node, new Node(waypoint.getCoor()))} 101 * instead 121 102 */ 103 @Deprecated 122 104 public static double getDistanceNode(Node node, WayPoint waypoint) { 123 if (node == null ) return Double.MAX_VALUE;124 return getDistanceLatLon(node.getCoor(), waypoint);105 if (node == null || waypoint == null) return Double.MAX_VALUE; 106 return Geometry.getDistance(node, new Node(waypoint.getCoor())); 125 107 } 126 108 127 109 /** … … 129 111 * @param en The EastNorth to get the distance to 130 112 * @param waypoint WayPoint to get the distance to 131 113 * @return The distance between the two points 114 * @deprecated Use {@code Geometry.getDistance(new Node(en), new Node(waypoint.getCoor()))} instead 132 115 */ 116 @Deprecated 133 117 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);118 if (en == null || waypoint == null) return Double.MAX_VALUE; 119 return Geometry.getDistance(new Node(en), new Node(waypoint.getCoor())); 136 120 } 137 121 138 122 /** … … 140 124 * @param latlon LatLon to get the distance from 141 125 * @param waypoint WayPoint to get the distance to 142 126 * @return The distance between the two points 127 * @deprecated Use {@code Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor()))} instead 143 128 */ 129 @Deprecated 144 130 public static double getDistanceLatLon(LatLon latlon, WayPoint waypoint) { 145 131 if (latlon == null || waypoint == null || waypoint.getCoor() == null) return Double.MAX_VALUE; 146 return waypoint.getCoor().greatCircleDistance(latlon);132 return Geometry.getDistance(new Node(latlon), new Node(waypoint.getCoor())); 147 133 } 148 134 } -
src/org/openstreetmap/josm/tools/Geometry.java
8 8 import java.math.BigDecimal; 9 9 import java.math.MathContext; 10 10 import java.util.ArrayList; 11 import java.util.Collection; 11 12 import java.util.Collections; 12 13 import java.util.Comparator; 13 14 import java.util.EnumSet; … … 30 31 import org.openstreetmap.josm.data.osm.MultipolygonBuilder.JoinedPolygon; 31 32 import org.openstreetmap.josm.data.osm.Node; 32 33 import org.openstreetmap.josm.data.osm.NodePositionComparator; 34 import org.openstreetmap.josm.data.osm.OsmPrimitive; 33 35 import org.openstreetmap.josm.data.osm.Relation; 34 36 import org.openstreetmap.josm.data.osm.Way; 37 import org.openstreetmap.josm.data.osm.WaySegment; 35 38 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon; 36 39 import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache; 37 40 import org.openstreetmap.josm.data.projection.Projection; … … 1070 1073 } 1071 1074 return new AreaAndPerimeter(Math.abs(area) / 2, perimeter); 1072 1075 } 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 } else if (one instanceof Relation && two instanceof Relation) { 1146 for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) { 1147 for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) { 1148 double currentDistance = getDistance(osmPrimitive1, osmPrimitive2); 1149 if (currentDistance < rValue) rValue = currentDistance; 1150 } 1151 } 1152 } 1153 return rValue; 1154 } 1155 1156 /** 1157 * Get the distance between a way and a node 1158 * @param way The way to get the distance from 1159 * @param node The node to get the distance to 1160 * @return The distance between the {@code way} and the {@code node} 1161 * @since xxx 1162 */ 1163 public static double getDistanceWayNode(Way way, Node node) { 1164 double rValue = Double.MAX_VALUE; 1165 if (way.getNodesCount() < 2) return rValue; 1166 List<WaySegment> segments = getWaySegments(way); 1167 for (WaySegment segment : segments) { 1168 EastNorth point = Geometry.closestPointToSegment(segment.getFirstNode().getEastNorth(), segment.getSecondNode().getEastNorth(), node.getEastNorth()); 1169 double distance = point.distance(node.getEastNorth()); 1170 if (distance < rValue) rValue = distance; 1171 } 1172 return rValue; 1173 } 1174 1175 /** 1176 * Get the closest {@code WaySegment} from a way to a primitive 1177 * @param way The {@code Way} to get the distance from and the {@code WaySegment} 1178 * @param primitive The {@code Primitive} to get the distance to 1179 * @return The {@code WaySegment} that is closest to {@code primitive} from {@code way} 1180 * @since xxx 1181 */ 1182 public static WaySegment getClosestWaySegment(Way way, OsmPrimitive primitive) { 1183 List<WaySegment> segments = getWaySegments(way); 1184 double lowestDistance = Double.MAX_VALUE; 1185 WaySegment closest = null; 1186 for (WaySegment segment : segments) { 1187 double distance = getDistance(segment.toWay(), primitive); 1188 if (distance < lowestDistance) { 1189 lowestDistance = distance; 1190 closest = segment; 1191 } 1192 } 1193 return closest; 1194 } 1195 1196 /** 1197 * Get the distance between different ways 1198 * @param one The way to get the distance from 1199 * @param two The {@code Way} to get the distance to 1200 * @return The shortest distance between the ways 1201 * @since xxx 1202 */ 1203 public static double getDistanceWayWay(Way one, Way two) { 1204 double rValue = Double.MAX_VALUE; 1205 List<WaySegment> oneSegments = getWaySegments(one); 1206 List<WaySegment> twoSegments = getWaySegments(two); 1207 for (WaySegment oneSegment : oneSegments) { 1208 for (WaySegment twoSegment : twoSegments) { 1209 EastNorth en1 = oneSegment.getFirstNode().getEastNorth(); 1210 EastNorth en2 = oneSegment.getSecondNode().getEastNorth(); 1211 EastNorth en3 = twoSegment.getFirstNode().getEastNorth(); 1212 EastNorth en4 = twoSegment.getSecondNode().getEastNorth(); 1213 if (en1 == null || en2 == null || en3 == null || en4 == null) continue; 1214 EastNorth intersection = Geometry.getSegmentSegmentIntersection( 1215 en1, en2, en3, en4); 1216 if (intersection != null) return 0.0; 1217 double distance = getDistanceSegmentSegment(oneSegment, twoSegment); 1218 if (distance < rValue) rValue = distance; 1219 } 1220 } 1221 return rValue; 1222 } 1223 1224 /** 1225 * Get the distance between different {@code WaySegment}s 1226 * @param one A {@code WaySegment} to get the distance from 1227 * @param two A {@code WaySegment} to get the distance to 1228 * @return The distance between the two {@code WaySegment}s 1229 * @since xxx 1230 */ 1231 public static double getDistanceSegmentSegment(WaySegment one, WaySegment two) { 1232 EastNorth vectorOne = one.getSecondNode().getEastNorth().subtract(one.getFirstNode().getEastNorth()); 1233 EastNorth vectorTwo = two.getSecondNode().getEastNorth().subtract(two.getFirstNode().getEastNorth()); 1234 EastNorth vectorThree = one.getFirstNode().getEastNorth().subtract(two.getFirstNode().getEastNorth()); 1235 double smallNumber = 0.00000000001; 1236 double a = dot(vectorOne, vectorOne); 1237 double b = dot(vectorOne, vectorTwo); 1238 double c = dot(vectorTwo, vectorTwo); 1239 double d = dot(vectorOne, vectorThree); 1240 double e = dot(vectorTwo, vectorThree); 1241 1242 double D = a * c - b * b; 1243 double sc, sN, sD = d; 1244 double tc, tN, tD = D; 1245 if (D < smallNumber) { 1246 sN = 0.0; 1247 sD = 1.0; 1248 tN = e; 1249 tD = c; 1250 } else { 1251 sN = (b * e - c * d); 1252 tN = (a * e - b * d); 1253 if (sN < 0.0) { 1254 sN = 0.0; 1255 tN = e; 1256 tD = c; 1257 } else if (sN > sD) { 1258 sN = sD; 1259 tN = e + b; 1260 tD = c; 1261 } 1262 } 1263 1264 if (tN < 0.0) { 1265 tN = 0.0; 1266 if (-d < 0.0) sN = 0.0; 1267 else if (-d > a) sN = sD; 1268 else { 1269 sN = -d; 1270 sD = a; 1271 } 1272 } else if (tN > tD) { 1273 tN = tD; 1274 if ((-d + b) < 0.0) sN = 0; 1275 else if ((-d + b) > a) sN = sD; 1276 else { 1277 sN = (-d + b); 1278 sD = a; 1279 } 1280 } 1281 sc = Math.abs(sN) < smallNumber ? 0.0 : sN / sD; 1282 tc = Math.abs(tN) < smallNumber ? 0.0 : tN / tD; 1283 EastNorth p1 = one.getFirstNode().getEastNorth().interpolate(one.getSecondNode().getEastNorth(), sc); 1284 EastNorth p2 = two.getFirstNode().getEastNorth().interpolate(two.getSecondNode().getEastNorth(), tc); 1285 return p1.distance(p2); 1286 } 1287 1288 /** 1289 * Get the dot product of two different EastNorth points 1290 * @param one The originating EastNorth 1291 * @param two The final EastNorth 1292 * @return the dot product of the EastNorths 1293 * @since xxx 1294 */ 1295 public static double dot(EastNorth one, EastNorth two) { 1296 return two.getX() * one.getX() + one.getY() * two.getY(); 1297 } 1298 1299 /** 1300 * Get the way segments of a way 1301 * @param way The way to get the way segments of 1302 * @return A lest of {@code WaySegment}s 1303 * @since xxx 1304 */ 1305 public static List<WaySegment> getWaySegments(Way way) { 1306 List<WaySegment> segments = new ArrayList<>(); 1307 int i = 0; 1308 do { 1309 segments.add(new WaySegment(way, i)); 1310 i++; 1311 } while (i < way.getNodesCount() - 2); 1312 return segments; 1313 } 1073 1314 } -
test/unit/org/openstreetmap/josm/tools/GeometryTest.java
4 4 import static org.junit.Assert.assertEquals; 5 5 6 6 import java.io.FileInputStream; 7 import java.util.ArrayList; 7 8 import java.util.Arrays; 8 9 import java.util.List; 9 10 … … 15 16 import org.openstreetmap.josm.data.coor.LatLon; 16 17 import org.openstreetmap.josm.data.osm.DataSet; 17 18 import org.openstreetmap.josm.data.osm.Node; 19 import org.openstreetmap.josm.data.osm.OsmPrimitive; 18 20 import org.openstreetmap.josm.data.osm.Relation; 21 import org.openstreetmap.josm.data.osm.RelationMember; 19 22 import org.openstreetmap.josm.data.osm.Way; 20 23 import org.openstreetmap.josm.data.osm.search.SearchCompiler; 21 24 import org.openstreetmap.josm.io.OsmReader; … … 158 161 assertEquals(new EastNorth(125, 300), Geometry.getCentroidEN(Arrays.asList(en1, en2))); 159 162 assertEquals(new EastNorth(150, 266d + 2d/3d), Geometry.getCentroidEN(Arrays.asList(en1, en2, en3))); 160 163 } 164 165 /** 166 * Test of {@link Geometry#getDistance} method. 167 */ 168 @Test 169 public void testGetDistance() { 170 Node node1 = new Node(new LatLon(0, 0)); 171 Node node2 = new Node(new LatLon(0, 1)); 172 Node node3 = new Node(new LatLon(1, 0)); 173 Node node4 = new Node(new LatLon(1, 1)); 174 Way way1 = new Way(); 175 way1.addNode(node1); 176 way1.addNode(node2); 177 Way way2 = new Way(); 178 way2.addNode(node3); 179 way2.addNode(node4); 180 Relation testRelation1 = new Relation(); 181 Relation testRelation2 = new Relation(); 182 testRelation1.addMember(new RelationMember("", way1)); 183 testRelation1.addMember(new RelationMember("", way2)); 184 testRelation2.addMember(new RelationMember("", node1)); 185 testRelation2.addMember(new RelationMember("", node2)); 186 testRelation2.addMember(new RelationMember("", node3)); 187 testRelation2.addMember(new RelationMember("", node4)); 188 189 double distance = Geometry.getDistance(null, node3); 190 assertEquals(Double.MAX_VALUE, distance, 0.1); 191 192 distance = Geometry.getDistance(way1, null); 193 assertEquals(Double.MAX_VALUE, distance, 0.1); 194 195 distance = Geometry.getDistance(null, null); 196 assertEquals(Double.MAX_VALUE, distance, 0.1); 197 198 distance = Geometry.getDistance(node1, node2); 199 assertEquals(111319.49079327357, distance, 0.1); 200 201 distance = Geometry.getDistance(way1, node3); 202 assertEquals(111325.1428663855, distance, 0.1); 203 204 distance = Geometry.getDistance(node3, way1); 205 assertEquals(111325.1428663855, distance, 0.1); 206 207 distance = Geometry.getDistance(way1, way2); 208 assertEquals(111325.1428663855, distance, 0.1); 209 210 distance = Geometry.getDistance(testRelation1, new Node(new LatLon(0, 0.5))); 211 assertEquals(0.0, distance, 0.1); 212 213 distance = Geometry.getDistance(new Node(new LatLon(0, 0.5)), testRelation1); 214 assertEquals(0.0, distance, 0.1); 215 216 distance = Geometry.getDistance(testRelation1, testRelation2); 217 assertEquals(0.0, distance, 0.1); 218 } 219 220 /** 221 * Test of {@link Geometry#getClosestPrimitive} method 222 */ 223 @Test 224 public void testGetClosestPrimitive() { 225 Node node1 = new Node(new LatLon(0, 0)); 226 Node node2 = new Node(new LatLon(0, 1)); 227 Node node3 = new Node(new LatLon(1, 0)); 228 Node node4 = new Node(new LatLon(1, 1)); 229 Way way1 = new Way(); 230 way1.addNode(node1); 231 way1.addNode(node2); 232 Way way2 = new Way(); 233 way2.addNode(node3); 234 way2.addNode(node4); 235 236 List<OsmPrimitive> primitives = new ArrayList<>(); 237 primitives.add(way1); 238 primitives.add(way2); 239 OsmPrimitive closest = Geometry.getClosestPrimitive(node1, primitives); 240 assertEquals(way1, closest); 241 } 242 243 /** 244 * Test of {@link Geometry#getFurthestPrimitive} method 245 */ 246 @Test 247 public void testGetFurthestPrimitive() { 248 Node node1 = new Node(new LatLon(0, 0)); 249 Node node2 = new Node(new LatLon(0, 1)); 250 Node node3 = new Node(new LatLon(1, 0)); 251 Node node4 = new Node(new LatLon(1, 1)); 252 Way way1 = new Way(); 253 way1.addNode(node1); 254 way1.addNode(node2); 255 Way way2 = new Way(); 256 way2.addNode(node3); 257 way2.addNode(node4); 258 259 List<OsmPrimitive> primitives = new ArrayList<>(); 260 primitives.add(way1); 261 primitives.add(way2); 262 OsmPrimitive furthest = Geometry.getFurthestPrimitive(node1, primitives); 263 assertEquals(way2, furthest); 264 } 265 266 /** 267 * Test of {@link Geometry#getClosestWaySegment} method 268 */ 269 @Test 270 public void testGetClosestWaySegment() { 271 Node node1 = new Node(new LatLon(0, 0)); 272 Node node2 = new Node(new LatLon(0, 1)); 273 Node node3 = new Node(new LatLon(1, 0)); 274 Node node4 = new Node(new LatLon(1, 1)); 275 Way way1 = new Way(); 276 way1.addNode(node1); 277 way1.addNode(node2); 278 way1.addNode(node3); 279 way1.addNode(node4); 280 281 Way closestSegment = Geometry.getClosestWaySegment(way1, new Node(new LatLon(0, 0.5))).toWay(); 282 Assert.assertTrue(closestSegment.containsNode(node1)); 283 Assert.assertTrue(closestSegment.containsNode(node2)); 284 } 161 285 }