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 + -
显示快捷键?