latlon.java
来自「world wind java sdk 源码」· Java 代码 · 共 943 行 · 第 1/3 页
JAVA
943 行
// equator will be antipodal (exactly 180 degrees opposite each other), as will be the extreme latitudes. // My observing the symmetry of a great circle, it is also apparent that the extreme latitudes will be 90 // degrees from either interseciton with the equator. // // d1 = c + 90 // d2 = c - 90 double tanDistance = - Math.tan(lat0) / Math.cos(az); double distance = Math.atan(tanDistance); Angle extremeDistance1 = Angle.fromRadians(distance + (Math.PI / 2.0)); Angle extremeDistance2 = Angle.fromRadians(distance - (Math.PI / 2.0)); return new LatLon[] { greatCircleEndPosition(location, azimuth, extremeDistance1), greatCircleEndPosition(location, azimuth, extremeDistance2) }; } /** * Returns two locations with the most extreme latitudes on the great circle arc defined by, and limited to, the * two locations. * * @param begin beginning location on the great circle arc. * @param end ending location on the great circle arc. * * @return two locations with the most extreme latitudes on the great circle arc. * @throws IllegalArgumentException if either <code>begin</code> or <code>end</code> are null. */ public static LatLon[] greatCircleArcExtremeLocations(LatLon begin, LatLon end) { if (begin == null) { String message = Logging.getMessage("nullValue.BeginIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (end == null) { String message = Logging.getMessage("nullValue.EndIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } LatLon minLatLocation = null; LatLon maxLatLocation = null; double minLat = Angle.POS90.degrees; double maxLat = Angle.NEG90.degrees; // Compute the min and max latitude and assocated locations from the arc endpoints. for (LatLon ll : java.util.Arrays.asList(begin, end)) { if (minLat > ll.getLatitude().degrees) { minLat = ll.getLatitude().degrees; minLatLocation = ll; } if (maxLat < ll.getLatitude().degrees) { maxLat = ll.getLatitude().degrees; maxLatLocation = ll; } } // Compute parameters for the great circle arc defined by begin and end. Then compute the locations of extreme // latitude on entire the great circle which that arc is part of. Angle greatArcAzimuth = greatCircleAzimuth(begin, end); Angle greatArcDistance = greatCircleDistance(begin, end); LatLon[] greatCircleExtremes = greatCircleExtremeLocations(begin, greatArcAzimuth); // Determine whether either of the extreme locations are inside the arc defined by begin and end. If so, // adjust the min and max latitude accordingly. for (LatLon ll : greatCircleExtremes) { Angle az = LatLon.greatCircleAzimuth(begin, ll); Angle d = LatLon.greatCircleDistance(begin, ll); // The extreme location must be between the begin and end locations. Therefore its azimuth relative to // the begin location should have the same signum, and its distance relative to the begin location should // be between 0 and greatArcDistance, inclusive. if (Math.signum(az.degrees) == Math.signum(greatArcAzimuth.degrees)) { if (d.degrees >= 0 && d.degrees <= greatArcDistance.degrees) { if (minLat > ll.getLatitude().degrees) { minLat = ll.getLatitude().degrees; minLatLocation = ll; } if (maxLat < ll.getLatitude().degrees) { maxLat = ll.getLatitude().degrees; maxLatLocation = ll; } } } } return new LatLon[] {minLatLocation, maxLatLocation}; } /** * Computes the length of the rhumb line between two locations. The return value gives the distance as the angular * distance between the two positions on the pi radius circle. In radians, this angle is also the arc length of the * segment between the two positions on that circle. To compute a distance in meters from this value, multiply it by * the radius of the globe. * * @param p1 LatLon of the first location * @param p2 LatLon of the second location * @return the arc length of the rhumb line between the two locations. In radians, this value is the arc length on * the radius pi circle. */ public static Angle rhumbDistance(LatLon p1, LatLon p2) { if (p1 == null || p2 == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } double lat1 = p1.getLatitude().radians; double lon1 = p1.getLongitude().radians; double lat2 = p2.getLatitude().radians; double lon2 = p2.getLongitude().radians; if (lat1 == lat2 && lon1 == lon2) return Angle.ZERO; // Taken from http://www.movable-type.co.uk/scripts/latlong.html double dLat = lat2 - lat1; double dLon = lon2 - lon1; double dPhi = Math.log(Math.tan(lat2 / 2.0 + Math.PI / 4.0) / Math.tan(lat1 / 2.0 + Math.PI / 4.0)); double q = dLat / dPhi; if (Double.isNaN(dPhi) || Double.isNaN(q)) { q = Math.cos(lat1); } // If lonChange over 180 take shorter rhumb across 180 meridian. if (Math.abs(dLon) > Math.PI) { dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); } double distanceRadians = Math.sqrt(dLat * dLat + q * q * dLon * dLon); return Double.isNaN(distanceRadians) ? Angle.ZERO : Angle.fromRadians(distanceRadians); } /** * Computes the azimuth angle (clockwise from North) of a rhumb line (a line of constant heading) between two * locations. * * @param p1 LatLon of the first location * @param p2 LatLon of the second location * @return azimuth Angle of a rhumb line between the two locations. */ public static Angle rhumbAzimuth(LatLon p1, LatLon p2) { if (p1 == null || p2 == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } double lat1 = p1.getLatitude().radians; double lon1 = p1.getLongitude().radians; double lat2 = p2.getLatitude().radians; double lon2 = p2.getLongitude().radians; if (lat1 == lat2 && lon1 == lon2) return Angle.ZERO; // Taken from http://www.movable-type.co.uk/scripts/latlong.html double dLon = lon2 - lon1; double dPhi = Math.log(Math.tan(lat2 / 2.0 + Math.PI / 4.0) / Math.tan(lat1 / 2.0 + Math.PI / 4.0)); // If lonChange over 180 take shorter rhumb across 180 meridian. if (Math.abs(dLon) > Math.PI) { dLon = dLon > 0 ? -(2 * Math.PI - dLon) : (2 * Math.PI + dLon); } double azimuthRadians = Math.atan2(dLon, dPhi); return Double.isNaN(azimuthRadians) ? Angle.ZERO : Angle.fromRadians(azimuthRadians); } /** * Computes the location on a rhumb line with the given starting location, rhumb azimuth, and arc distance along the * line. * * @param p LatLon of the starting location * @param rhumbAzimuth rhumb azimuth angle (clockwise from North) * @param pathLength arc distance to travel * @return LatLon location on the rhumb line. */ public static LatLon rhumbEndPosition(LatLon p, Angle rhumbAzimuth, Angle pathLength) { if (p == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (rhumbAzimuth == null || pathLength == null) { String message = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } double lat1 = p.getLatitude().radians; double lon1 = p.getLongitude().radians; double azimuth = rhumbAzimuth.radians; double distance = pathLength.radians; if (distance == 0) return p; // Taken from http://www.movable-type.co.uk/scripts/latlong.html double lat2 = lat1 + distance * Math.cos(azimuth); double dPhi = Math.log(Math.tan(lat2 / 2.0 + Math.PI / 4.0) / Math.tan(lat1 / 2.0 + Math.PI / 4.0)); double q = (lat2 - lat1) / dPhi; if (Double.isNaN(dPhi) || Double.isNaN(q) || Double.isInfinite(q)) { q = Math.cos(lat1); } double dLon = distance * Math.sin(azimuth) / q; // Handle latitude passing over either pole. if (Math.abs(lat2) > Math.PI / 2.0) { lat2 = lat2 > 0 ? Math.PI - lat2 : -Math.PI - lat2; } double lon2 = (lon1 + dLon + Math.PI) % (2 * Math.PI) - Math.PI; if (Double.isNaN(lat2) || Double.isNaN(lon2)) return p; return new LatLon( Angle.fromRadians(lat2).normalizedLatitude(), Angle.fromRadians(lon2).normalizedLongitude()); } /** * Computes the location on a rhumb line with the given starting location, rhumb azimuth, and arc distance along the * line. * * @param p LatLon of the starting location * @param rhumbAzimuthRadians rhumb azimuth angle (clockwise from North), in radians * @param pathLengthRadians arc distance to travel, in radians * @return LatLon location on the rhumb line. */ public static LatLon rhumbEndPosition(LatLon p, double rhumbAzimuthRadians, double pathLengthRadians) { if (p == null) { String message = Logging.getMessage("nullValue.LatLonIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } return rhumbEndPosition(p, Angle.fromRadians(rhumbAzimuthRadians), Angle.fromRadians(pathLengthRadians)); } public static Angle getAverageDistance(Iterable<? extends LatLon> locations) { // Compute the average rhumb distance between locations. if ((locations == null)) { String msg = Logging.getMessage("nullValue.LocationsListIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } double totalDistance = 0.0; int count = 0; for (LatLon p1 : locations) { for (LatLon p2 : locations) { if (p1 != p2) { double d = rhumbDistance(p1, p2).radians; totalDistance += d; count++; } } } return (count == 0) ? Angle.ZERO : Angle.fromRadians(totalDistance / (double) count); } public LatLon add(LatLon that) { if (that == null) { String msg = Logging.getMessage("nullValue.AngleIsNull"); Logging.logger().severe(msg); throw new IllegalArgumentException(msg); } Angle lat = Angle.normalizedLatitude(this.latitude.add(that.latitude)); Angle lon = Angle.normalizedLongitude(this.longitude.add(that.longitude)); return new LatLon(lat, lon); } public LatLon subtract(LatLon that) { if (that == null) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?