All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.unidata.geoloc.LatLonPointImpl Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */
package ucar.unidata.geoloc;

import ucar.nc2.util.Misc;

import java.util.Formatter;

/**
 * Standard implementation of LatLonPoint.
 * Longitude is always between -180 and +180 deg.
 * Latitude is always between -90 and +90 deg.
 *
 * @author Russ Rew
 * @author John Caron
 * @see LatLonPoint
 */
public class LatLonPointImpl implements LatLonPoint, java.io.Serializable {

  /**
   * Test if point lies between two longitudes, deal with wrapping.
   *
   * @param lon    point to test
   * @param lonBeg beginning longitude
   * @param lonEnd ending longitude
   * @return true if lon is between lonBeg and lonEnd.
   * @deprecated
   */
  static public boolean betweenLon(double lon, double lonBeg, double lonEnd) {
    lonBeg = lonNormal(lonBeg, lon);
    lonEnd = lonNormal(lonEnd, lon);
    return (lon >= lonBeg) && (lon <= lonEnd);
  }

  static public double getClockwiseDistanceTo(double from, double to) {
    double distance = to - from;
    while (distance < 0.0)
      distance += 360.0;
    return distance;
  }


  /**
   * put longitude into the range [-180, 180] deg
   *
   * @param lon lon to normalize
   * @return longitude in range [-180, 180] deg
   */
  static public double range180(double lon) {
    return lonNormal(lon);
  }

  /**
   * put longitude into the range [0, 360] deg
   *
   * @param lon lon to normalize
   * @return longitude into the range [0, 360] deg
   */
  static public double lonNormal360(double lon) {
    return lonNormal(lon, 180.0);
  }

  /**
   * put longitude into the range [center +/- 180] deg
   *
   * @param lon    lon to normalize
   * @param center center point
   * @return longitude into the range [center +/- 180] deg
   */
  static public double lonNormal(double lon, double center) {
    return center + Math.IEEEremainder(lon - center, 360.0);
  }

  /**
   * put longitude into the range [start, start+360] deg
   *
   * @param lon    lon to normalize
   * @param start starting point
   * @return longitude into the [start, start+360] deg
   */
  static public double lonNormalFrom(double lon, double start) {
    while (lon < start) lon += 360;
    while (lon > start+360) lon -= 360;
    return lon;
  }

  /**
   * Normalize the longitude to lie between +/-180
   *
   * @param lon east latitude in degrees
   * @return normalized lon
   */
  static public double lonNormal(double lon) {
    if ((lon < -180.) || (lon > 180.)) {
      return Math.IEEEremainder(lon, 360.0);
    } else {
      return lon;
    }
  }

  /**
   * Find difference (lon1 - lon2) normalized so that maximum value is += 180.
   * @param lon1 start
   * @param lon2 end
   * @return
   */
  static public double lonDiff(double lon1, double lon2) {
    return Math.IEEEremainder(lon1-lon2, 360.0);
  }

  /**
   * Normalize the latitude to lie between +/-90
   *
   * @param lat north latitude in degrees
   * @return normalized lat
   */
  static public double latNormal(double lat) {
    if (lat < -90.) {
      return -90.;
    } else if (lat > 90.) {
      return 90.;
    } else {
      return lat;
    }
  }

  /**
   * Make a nicely formatted representation of a latitude, eg 40.34N or 12.9S.
   *
   * @param lat       the latitude.
   * @param ndec      number of digits to right of decimal point
   * @return String representation.
   */
  static public String latToString(double lat, int ndec) {
    boolean is_north = (lat >= 0.0);
    if (!is_north)
      lat = -lat;

    String f = "%."+ndec+"f";

    Formatter latBuff = new Formatter();
    latBuff.format(f, lat);
    latBuff.format("%s", is_north ? "N" : "S");

    return latBuff.toString();
  }

  /**
   * Make a nicely formatted representation of a longitude, eg 120.3W or 99.99E.
   *
   * @param lon       the longitude.
   * @param ndec      number of digits to right of decimal point
   * @return String representation.
   */
  static public String lonToString(double lon, int ndec) {
    double wlon = lonNormal(lon);
    boolean is_east = (wlon >= 0.0);
    if (!is_east)
      wlon = -wlon;

    String f = "%."+ndec+"f";

    Formatter latBuff = new Formatter();
    latBuff.format(f, wlon);
    latBuff.format("%s", is_east ? "E" : "W");

    return latBuff.toString();
  }

  ///////////////////////////////////////////////////////////////////////////////////

  /**
   * East latitude in degrees, always +/- 90
   */
  protected double lat;

  /**
   * North longitude in degrees, always +/- 180
   */
  protected double lon;

  /**
   * Default constructor with values 0,0.
   */
  public LatLonPointImpl() {
    // Don't initialize by calling setLatitude() and setLongitude(), as those methods throw
    // UnsupportedOperationException in LatLonPointImmutable, and this constructor is (implicitly) invoked in the
    // LatLonPointImmutable constructors.
    this.lat = 0;
    this.lon = 0;
  }

  /**
   * Copy Constructor.
   *
   * @param pt point to copy
   */
  public LatLonPointImpl(LatLonPoint pt) {
    this(pt.getLatitude(), pt.getLongitude());
  }

  /**
   * Creates a LatLonPoint from component latitude and longitude values.
   * The longitude is adjusted to be in the range [-180.,180.].
   *
   * @param lat north latitude in degrees
   * @param lon east longitude in degrees
   */
  public LatLonPointImpl(double lat, double lon) {
    setLatitude(lat);
    setLongitude(lon);
  }

  /**
   * Returns the longitude, in degrees.
   *
   * @return the longitude, in degrees
   */
  public double getLongitude() {
    return lon;
  }

  /**
   * Returns the latitude, in degrees.
   *
   * @return the latitude, in degrees
   */
  public double getLatitude() {
    return lat;
  }

  /**
   * set lat, lon using values of pt
   *
   * @param pt point to use
   */
  public void set(LatLonPoint pt) {
    setLongitude(pt.getLongitude());
    setLatitude(pt.getLatitude());
  }

  /**
   * set lat, lon using double values
   *
   * @param lat lat value
   * @param lon lon value
   */
  public void set(double lat, double lon) {
    setLongitude(lon);
    setLatitude(lat);
  }

  /**
   * set lat, lon using float values
   *
   * @param lat lat value
   * @param lon lon value
   */
  public void set(float lat, float lon) {
    setLongitude((double) lon);
    setLatitude((double) lat);
  }

  /**
   * Set the longitude, in degrees. It is normalized to +/-180.
   *
   * @param lon east longitude in degrees
   */
  public void setLongitude(double lon) {
    this.lon = lonNormal(lon);
  }

  /**
   * Set the latitude, in degrees. Must lie beween +/-90
   *
   * @param lat north latitude in degrees
   */
  public void setLatitude(double lat) {
    this.lat = latNormal(lat);
  }

  @Override
  public boolean nearlyEquals(LatLonPoint that, double maxRelDiff) {
    boolean lonOk = Misc.nearlyEquals(that.getLongitude(), this.lon, maxRelDiff);
    if (!lonOk) {
      // We may be in a situation where "this.lon ≈ -180" and "that.lon ≈ +180", or vice versa.
      // Those longitudes are equivalent, but not "nearlyEquals()". So, we normalize them both to lie in
      // [0, 360] and compare them again.
      lonOk = Misc.nearlyEquals(lonNormal360(that.getLongitude()), lonNormal360(this.lon), maxRelDiff);
    }
    return lonOk && Misc.nearlyEquals(that.getLatitude(), this.lat, maxRelDiff);
  }

  // Exact comparison is needed in order to be consistent with hashCode().
  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    }
    if (!(other instanceof LatLonPoint)) {
      return false;
    }
    LatLonPoint that = (LatLonPoint) other;
    if (Double.compare(that.getLatitude(), this.getLatitude()) != 0) {
      return false;
    }
    return Double.compare(that.getLongitude(), this.getLongitude()) == 0;
  }

  @Override
  public int hashCode() {
    int result;
    long temp;
    temp = Double.doubleToLongBits(lat);
    result = (int) (temp ^ (temp >>> 32));
    temp = Double.doubleToLongBits(lon);
    result = 31 * result + (int) (temp ^ (temp >>> 32));
    return result;
  }

  /**
   * Default string representation
   *
   * @return string representing this point
   */
  public String toString() {
    return toString(4);
  }

  /**
   * String representation in the form, eg 40.23N 105.1W
   *
   * @param sigDigits significant digits
   * @return String representation
   */
  public String toString(int sigDigits) {
    Formatter sbuff = new Formatter();
    sbuff.format("%s %s", latToString(lat, sigDigits), lonToString(lon, sigDigits));
    return sbuff.toString();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy