Ticket #17388: 17388.4.patch
File 17388.4.patch, 18.6 KB (added by , 3 years ago) |
---|
-
src/org/openstreetmap/josm/data/coor/EastNorth.java
12 12 13 13 private static final long serialVersionUID = 1L; 14 14 15 /** Set on valid when the east north is valid */ 16 private static final byte IS_VALID = 1; 17 /** Set on valid when east north is not valid */ 18 private static final byte IS_INVALID = 2; 15 19 /** 20 * If {@link #IS_VALID}, return {#code true}. If {@link #IS_INVALID}, return {@code false}. 21 * Otherwise, run {@link #updateValid}. Default value is {@code 0}. 22 */ 23 private byte valid; 24 25 /** 16 26 * A zero constant 17 27 */ 18 28 public static final EastNorth ZERO = new EastNorth(0, 0); … … 153 163 * @return true if east and north are different from Double.NaN and not infinite 154 164 */ 155 165 public boolean isValid() { 156 return !Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y); 166 /* Most of the time, EastNorth should be valid. When it isn't cached, and not IS_INVALID, 167 * update and cache the validity of the east north. */ 168 return this.valid == IS_VALID || (this.valid == 0 && updateValid()); 157 169 } 158 170 171 private boolean updateValid() { 172 if (!Double.isNaN(x) && !Double.isNaN(y) && !Double.isInfinite(x) && !Double.isInfinite(y)) { 173 this.valid = IS_VALID; 174 } else { 175 this.valid = IS_INVALID; 176 } 177 return this.valid == IS_VALID; 178 } 179 159 180 /** 160 181 * Returns an EastNorth representing the this EastNorth rotated around 161 182 * a given EastNorth by a given angle -
src/org/openstreetmap/josm/data/gpx/GpxDistance.java
1 1 // License: GPL. For details, see LICENSE file. 2 2 package org.openstreetmap.josm.data.gpx; 3 3 4 import org.openstreetmap.josm.data.osm.Node; 4 import java.util.OptionalDouble; 5 6 import org.openstreetmap.josm.data.coor.ILatLon; 7 import org.openstreetmap.josm.data.coor.LatLon; 8 import org.openstreetmap.josm.data.osm.BBox; 5 9 import org.openstreetmap.josm.data.osm.OsmPrimitive; 10 import org.openstreetmap.josm.data.projection.Ellipsoid; 11 import org.openstreetmap.josm.data.projection.ProjectionRegistry; 12 import org.openstreetmap.josm.data.projection.datum.WGS84Datum; 6 13 import org.openstreetmap.josm.tools.Geometry; 7 14 8 15 /** … … 23 30 * @return The shortest distance 24 31 */ 25 32 public static double getLowestDistance(OsmPrimitive p, GpxData gpxData) { 26 return gpxData.getTrackPoints()27 .mapToDouble(tp -> Geometry.getDistance (p, new Node(tp.getCoor())))28 .filter(x -> x >= 0) 29 .min().orElse(Double.MAX_VALUE);33 OptionalDouble min = gpxData.getTrackPoints().map(waypoint -> waypoint.getEastNorth(ProjectionRegistry.getProjection())) 34 .mapToDouble(tp -> Geometry.getDistanceSq(p, tp)) 35 .filter(x -> x >= 0).min(); 36 return min.isPresent() ? Math.sqrt(min.getAsDouble()) : Double.MAX_VALUE; 30 37 } 38 39 /** 40 * Find the distance between a point and a dataset of surveyed points 41 * @param p OsmPrimitive from which to get the lowest distance to a GPX point 42 * @param gpxData Data from which to get the GPX points 43 * @param maxDistance The maximum distance to look (LatLon distance) 44 * @return The shortest distance 45 */ 46 public static double getLowestDistance(OsmPrimitive p, GpxData gpxData, double maxDistance) { 47 BBox onlyInside = p.getBBox(); 48 Ellipsoid ellipsoid = WGS84Datum.INSTANCE.getEllipsoid(); 49 ILatLon centroid = p.getBBox().getCenter(); 50 // This probably isn't the best method, but this should work. TODO 51 double dLat = maxDistance / (111132.954 - 559.822 * Math.cos(2 * centroid.lat()) + 1.175 * Math.cos(4 * centroid.lat())); 52 // This is currently ~4x the actual. 53 double dLong = maxDistance / (Math.PI * ellipsoid.a * Math.cos(centroid.lat()) 54 / (180 * Math.sqrt(1 - ellipsoid.e2 * Math.pow(Math.sin(centroid.lat()), 2)))); 55 dLong = dLong / 4; 56 LatLon lowerRight = new LatLon(onlyInside.getBottomRightLat() - dLat, onlyInside.getBottomRightLon() + dLong); 57 LatLon upperLeft = new LatLon(onlyInside.getTopLeftLat() + dLat, onlyInside.getTopLeftLon() - dLong); 58 onlyInside.add(lowerRight); 59 onlyInside.add(upperLeft); 60 // TODO if GpxData ever implements OsmData, use the searchNodes method. 61 OptionalDouble min = gpxData.getTrackPoints().filter(onlyInside::bounds) 62 .map(waypoint -> waypoint.getEastNorth(ProjectionRegistry.getProjection())) 63 .mapToDouble(tp -> Geometry.getDistanceSq(p, tp)) 64 .filter(x -> x >= 0).min(); 65 return min.isPresent() ? Math.sqrt(min.getAsDouble()) : Double.MAX_VALUE; 66 } 31 67 } -
src/org/openstreetmap/josm/data/osm/BBox.java
236 236 * Tests, whether the Point {@code c} lies within the bbox. 237 237 * @param c point 238 238 * @return {@code true} if {@code c} lies within the bbox 239 * @deprecated use {@link #bounds(ILatLon)} instead. Casting may be required. This will eventually become unnecessary. 239 240 */ 241 @Deprecated 240 242 public boolean bounds(LatLon c) { 243 return bounds((ILatLon) c); 244 } 245 246 /** 247 * Tests, whether the Point {@code c} lies within the bbox. 248 * @param c point 249 * @return {@code true} if {@code c} lies within the bbox 250 * @since xxx 251 */ 252 public boolean bounds(ILatLon c) { 241 253 return xmin <= c.lon() && xmax >= c.lon() 242 && ymin <= c.lat() && ymax >= c.lat();254 && ymin <= c.lat() && ymax >= c.lat(); 243 255 } 244 256 245 257 /** -
src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java
513 513 * @param env the environment 514 514 * @return the distance between the object and the closest gpx point or {@code Double.MAX_VALUE} 515 515 * @since 14802 516 * @deprecated Use {@link #gpx_distance(Environment, float)} instead. There is a major performance improvement. 516 517 */ 518 @Deprecated 517 519 public static double gpx_distance(final Environment env) { // NO_UCD (unused code) 518 520 if (env.osm instanceof OsmPrimitive) { 519 521 return MainApplication.getLayerManager().getAllGpxData().stream() … … 524 526 } 525 527 526 528 /** 529 * Returns the lowest distance between the OSM object and a GPX point 530 * <p> 531 * @param env the environment 532 * @param maxDistance The maximum distance to consider 533 * @return the distance between the object and the closest gpx point or {@code Double.MAX_VALUE} 534 * @since xxx 535 */ 536 public static double gpx_distance(final Environment env, final float maxDistance) { // NO_UCD (unused code) 537 if (env.osm instanceof OsmPrimitive) { 538 return MainApplication.getLayerManager().getAllGpxData().stream() 539 .mapToDouble(gpx -> GpxDistance.getLowestDistance((OsmPrimitive) env.osm, gpx, maxDistance)) 540 .min().orElse(Double.MAX_VALUE); 541 } 542 return Double.MAX_VALUE; 543 } 544 545 /** 527 546 * Determines whether the object has a tag with the given key. 528 547 * @param env the environment 529 548 * @param key the OSM key -
src/org/openstreetmap/josm/tools/Geometry.java
1303 1303 double lowestDistance = Double.MAX_VALUE; 1304 1304 TreeSet<T> closest = new TreeSet<>(); 1305 1305 for (T primitive : primitives) { 1306 double distance = getDistance (osm, primitive);1306 double distance = getDistanceSq(osm, primitive); 1307 1307 if (Double.isNaN(distance)) continue; 1308 1308 int comp = Double.compare(distance, lowestDistance); 1309 1309 if (comp < 0) { … … 1367 1367 double furthestDistance = Double.NEGATIVE_INFINITY; 1368 1368 TreeSet<T> furthest = new TreeSet<>(); 1369 1369 for (T primitive : primitives) { 1370 double distance = getDistance (osm, primitive);1370 double distance = getDistanceSq(osm, primitive); 1371 1371 if (Double.isNaN(distance)) continue; 1372 1372 int comp = Double.compare(distance, furthestDistance); 1373 1373 if (comp > 0) { … … 1394 1394 * @since 15035 1395 1395 */ 1396 1396 public static double getDistance(OsmPrimitive one, OsmPrimitive two) { 1397 double distance = getDistanceSq(one, two); 1398 return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN; 1399 } 1400 1401 /** 1402 * Get the distance squared between different {@link OsmPrimitive}s 1403 * @param one The primitive to get the distance from 1404 * @param two The primitive to get the distance to 1405 * @return The distance squared between the primitives in meters 1406 * (or the unit of the current projection, see {@link Projection}). 1407 * May return {@link Double#NaN} if one of the primitives is incomplete. 1408 * 1409 * Note: The complexity is O(n*m), where (n,m) are the number of child 1410 * objects the {@link OsmPrimitive}s have. 1411 * @since xxx 1412 */ 1413 public static double getDistanceSq(OsmPrimitive one, OsmPrimitive two) { 1397 1414 double rValue = Double.MAX_VALUE; 1398 1415 if (one == null || two == null || one.isIncomplete() 1399 1416 || two.isIncomplete()) return Double.NaN; 1400 1417 if (one instanceof Node && two instanceof Node) { 1401 rValue = ((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor());1418 rValue = Math.pow(((Node) one).getCoor().greatCircleDistance(((Node) two).getCoor()), 2); 1402 1419 } else if (one instanceof Node && two instanceof Way) { 1403 rValue = getDistanceWay Node((Way) two, (Node) one);1420 rValue = getDistanceWayEastNorthSq((Way) two, ((Node) one).getEastNorth()); 1404 1421 } else if (one instanceof Way && two instanceof Node) { 1405 rValue = getDistanceWay Node((Way) one, (Node) two);1422 rValue = getDistanceWayEastNorthSq((Way) one, ((Node) two).getEastNorth()); 1406 1423 } else if (one instanceof Way && two instanceof Way) { 1407 rValue = getDistanceWayWay ((Way) one, (Way) two);1424 rValue = getDistanceWayWaySq((Way) one, (Way) two); 1408 1425 } else if (one instanceof Relation && !(two instanceof Relation)) { 1409 1426 for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) { 1410 double currentDistance = getDistance (osmPrimitive, two);1427 double currentDistance = getDistanceSq(osmPrimitive, two); 1411 1428 if (currentDistance < rValue) rValue = currentDistance; 1412 1429 } 1413 1430 } else if (!(one instanceof Relation) && two instanceof Relation) { 1414 rValue = getDistance (two, one);1431 rValue = getDistanceSq(two, one); 1415 1432 } else if (one instanceof Relation && two instanceof Relation) { 1416 1433 for (OsmPrimitive osmPrimitive1 : ((Relation) one).getMemberPrimitives()) { 1417 1434 for (OsmPrimitive osmPrimitive2 : ((Relation) two).getMemberPrimitives()) { 1418 double currentDistance = getDistance (osmPrimitive1, osmPrimitive2);1435 double currentDistance = getDistanceSq(osmPrimitive1, osmPrimitive2); 1419 1436 if (currentDistance < rValue) rValue = currentDistance; 1420 1437 } 1421 1438 } 1422 1439 } 1423 return rValue != Double.MAX_VALUE ? rValue : Double.NaN;1440 return rValue; 1424 1441 } 1425 1442 1426 1443 /** 1444 * Get the distance between a {@link OsmPrimitive} and a position 1445 * @param one The primitive to get the distance from 1446 * @param two The EastNorth to get the distance to 1447 * @return The distance between the objects in meters 1448 * (or the unit of the current projection, see {@link Projection}). 1449 * May return {@link Double#NaN} if one of the objects is incomplete. 1450 * 1451 * Note: The complexity is O(n*m), where (n,m) are the number of child 1452 * objects the {@link OsmPrimitive} have. 1453 * @since xxx 1454 */ 1455 public static double getDistanceSq(OsmPrimitive one, EastNorth two) { 1456 double rValue = Double.MAX_VALUE; 1457 if (one == null || two == null || one.isIncomplete() 1458 || !two.isValid()) return Double.NaN; 1459 if (one instanceof Node) { 1460 rValue = two.distanceSq(((Node) one).getEastNorth()); 1461 } else if (one instanceof Way) { 1462 rValue = getDistanceWayEastNorthSq((Way) one, two); 1463 } else if (one instanceof Relation) { 1464 for (OsmPrimitive osmPrimitive: ((Relation) one).getMemberPrimitives()) { 1465 double currentDistance = getDistanceSq(osmPrimitive, two); 1466 if (currentDistance < rValue) rValue = currentDistance; 1467 } 1468 } 1469 return rValue; 1470 } 1471 1472 /** 1427 1473 * Get the distance between a way and a node 1428 1474 * @param way The way to get the distance from 1429 1475 * @param node The node to get the distance to … … 1435 1481 public static double getDistanceWayNode(Way way, Node node) { 1436 1482 if (way == null || node == null || way.getNodesCount() < 2 || !node.isLatLonKnown()) 1437 1483 return Double.NaN; 1484 double distanceSq = getDistanceWayEastNorthSq(way, node.getEastNorth()); 1485 return distanceSq != Double.MAX_VALUE && !Double.isNaN(distanceSq) ? Math.sqrt(distanceSq) : distanceSq; 1486 } 1438 1487 1488 /** 1489 * Get the distance between a way and a node squared 1490 * @param way The way to get the distance from 1491 * @param eastNorth The EastNorth to get the distance to 1492 * @return The distance between the {@code way} and the {@code eastnorth} in 1493 * meters (or the unit of the current projection, see {@link Projection}). 1494 * May return {@link Double#NaN} if the primitives are incomplete. 1495 * @since xxx 1496 */ 1497 public static double getDistanceWayEastNorthSq(Way way, EastNorth eastNorth) { 1498 if (way == null || eastNorth == null || way.getNodesCount() < 2 || !eastNorth.isValid()) 1499 return Double.NaN; 1500 1439 1501 double smallest = Double.MAX_VALUE; 1440 EastNorth en0 = node.getEastNorth();1441 1502 // go through the nodes as if they were paired 1442 1503 Iterator<Node> iter = way.getNodes().iterator(); 1443 1504 EastNorth en1 = iter.next().getEastNorth(); 1444 1505 while (iter.hasNext()) { 1445 1506 EastNorth en2 = iter.next().getEastNorth(); 1446 double distance = getSegmentNodeDistSq(en1, en2, e n0);1507 double distance = getSegmentNodeDistSq(en1, en2, eastNorth); 1447 1508 if (distance < smallest) 1448 1509 smallest = distance; 1449 1510 en1 = en2; 1450 1511 } 1451 return smallest != Double.MAX_VALUE ? Math.sqrt(smallest): Double.NaN;1512 return smallest != Double.MAX_VALUE ? smallest : Double.NaN; 1452 1513 } 1453 1514 1454 1515 /** … … 1492 1553 * @since 15035 1493 1554 */ 1494 1555 public static double getDistanceWayWay(Way w1, Way w2) { 1556 double distance = getDistanceWayWaySq(w1, w2); 1557 return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN; 1558 } 1559 1560 /** 1561 * 1562 * Get the distance squared between different ways. Iterates over the nodes of the ways, complexity is O(n*m) 1563 * (n,m giving the number of nodes) 1564 * @param w1 The first {@link Way} 1565 * @param w2 The second {@link Way} 1566 * @return The shortest distance squared between the ways in meters 1567 * (or the unit of the current projection, see {@link Projection}). 1568 * May return {@link Double#NaN}. 1569 * @since xxx 1570 */ 1571 public static double getDistanceWayWaySq(Way w1, Way w2) { 1495 1572 if (w1 == null || w2 == null || w1.getNodesCount() < 2 || w2.getNodesCount() < 2) 1496 1573 return Double.NaN; 1497 1574 double rValue = Double.MAX_VALUE; … … 1503 1580 Node w2N1 = iter2.next(); 1504 1581 while (iter2.hasNext()) { 1505 1582 Node w2N2 = iter2.next(); 1506 double distance = getDistanceSegmentSegment (w1N1, w1N2, w2N1, w2N2);1583 double distance = getDistanceSegmentSegmentSq(w1N1, w1N2, w2N1, w2N2); 1507 1584 if (distance < rValue) 1508 1585 rValue = distance; 1509 1586 w2N1 = w2N2; … … 1538 1615 * @since 15035 1539 1616 */ 1540 1617 public static double getDistanceSegmentSegment(Node ws1Node1, Node ws1Node2, Node ws2Node1, Node ws2Node2) { 1618 double distance = getDistanceSegmentSegmentSq(ws1Node1, ws1Node2, ws2Node1, ws2Node2); 1619 return distance != Double.MAX_VALUE && !Double.isNaN(distance) ? Math.sqrt(distance) : Double.NaN; 1620 } 1621 1622 /** 1623 * Get the distance squared between different {@link WaySegment}s 1624 * @param ws1Node1 The first node of the first WaySegment 1625 * @param ws1Node2 The second node of the second WaySegment 1626 * @param ws2Node1 The first node of the second WaySegment 1627 * @param ws2Node2 The second node of the second WaySegment 1628 * @return The distance squared between the two {@link WaySegment}s in meters 1629 * (or the unit of the current projection, see {@link Projection}). 1630 * May return {@link Double#NaN} or {@link Double#MAX_VALUE}. 1631 * @since xxx 1632 */ 1633 public static double getDistanceSegmentSegmentSq(Node ws1Node1, Node ws1Node2, Node ws2Node1, Node ws2Node2) { 1541 1634 EastNorth enWs1Node1 = ws1Node1.getEastNorth(); 1542 1635 EastNorth enWs1Node2 = ws1Node2.getEastNorth(); 1543 1636 EastNorth enWs2Node1 = ws2Node1.getEastNorth(); … … 1551 1644 double dist2sq = getSegmentNodeDistSq(enWs1Node1, enWs1Node2, enWs2Node2); 1552 1645 double dist3sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node1); 1553 1646 double dist4sq = getSegmentNodeDistSq(enWs2Node1, enWs2Node2, enWs1Node2); 1554 double smallest = Math.min(Math.min(dist1sq, dist2sq), Math.min(dist3sq, dist4sq)); 1555 return smallest != Double.MAX_VALUE ? Math.sqrt(smallest) : Double.NaN; 1647 return Math.min(Math.min(dist1sq, dist2sq), Math.min(dist3sq, dist4sq)); 1556 1648 } 1557 1649 1558 1650 /**