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

ucar.unidata.geoloc.projection.LatLonProjection Maven / Gradle / Ivy

/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */
package ucar.unidata.geoloc.projection;

import ucar.unidata.geoloc.*;

import ucar.unidata.util.Format;

/**
 * This is the "fake" identity projection where world coord = latlon coord.
 * Topologically its the same as a cylinder tangent to the earth at the equator.
 * The cylinder is cut at the "seam" = centerLon +- 180.
 * Longitude values are always kept in the range [centerLon +-180]
 *
 * @author John Caron
 * @see ProjectionImpl
 */


public class LatLonProjection extends ProjectionImpl {

  /**
   * center longitude
   */
  private double centerLon = 0.0;

  /**
   * copy constructor - avoid clone !!
   */
  public ProjectionImpl constructCopy() {
    return new LatLonProjection(getName(), getDefaultMapArea());
  }

  /**
   * Default constructor
   */
  public LatLonProjection() {
    this("");
  }

  /**
   * Create a new LatLonProjection
   *
   * @param name name of projection
   */
  public LatLonProjection(String name) {
    this(name, new ProjectionRect(-180, -90, 180, 90));
  }

  /**
   * Create a new LatLonProjection
   *
   * @param name           name of projection
   * @param defaultMapArea bounding box
   */
  public LatLonProjection(String name, ProjectionRect defaultMapArea) {
    addParameter(ATTR_NAME, "latitude_longitude");
    this.name = name;
    isLatLon = true;
    this.defaultMapArea = defaultMapArea;
  }


  /**
   * Get the class name
   *
   * @return class name
   */
  public String getClassName() {
    return "latitude_longitude";
  }


  /**
   * Get the label to be used in the gui for this type of projection
   *
   * @return Type label
   */
  public String getProjectionTypeLabel() {
    return "Lat/Lon";
  }

  /**
   * Get a String of the parameters
   *
   * @return a String of the parameters
   */
  public String paramsToString() {
    return "Center lon:" + Format.d(centerLon, 3);
  }


  /**
   * See if this projection equals the object in question
   *
   * @param p object in question
   * @return true if it is a LatLonProjection and covers the same area
   */
  public boolean equals(Object p) {
    if (!(p instanceof LatLonProjection)) {
      return false;
    }
    LatLonProjection that = (LatLonProjection) p;
    return that.defaultMapArea.equals(this.defaultMapArea)
        && (Double.doubleToLongBits(that.centerLon)
        == Double.doubleToLongBits(this.centerLon));
  }

  /**
   * Convert a LatLonPoint to projection coordinates
   *
   * @param latlon convert from these lat, lon coordinates
   * @param result the object to write to
   * @return the given result
   */
  public ProjectionPoint latLonToProj(LatLonPoint latlon,
                                      ProjectionPointImpl result) {
    result.setLocation(LatLonPointImpl.lonNormal(latlon.getLongitude(),
        centerLon), latlon.getLatitude());
    return result;
  }

  /**
   * Convert projection coordinates to a LatLonPoint
   * Note: a new object is not created on each call for the return value.
   *
   * @param world  convert from these projection coordinates
   * @param result the object to write to
   * @return LatLonPoint convert to these lat/lon coordinates
   */
  public LatLonPoint projToLatLon(ProjectionPoint world,
                                  LatLonPointImpl result) {
    result.setLongitude(world.getX());
    result.setLatitude(world.getY());
    return result;
  }


  /**
   * Convert projection coordinates to lat/lon coordinate.
   *
   * @param from array of projection coordinates: from[2][n], where
   *             (from[0][i], from[1][i]) is the (x, y) coordinate
   *             of the ith point
   * @param to   resulting array of lat/lon coordinates: to[2][n] where
   *             (to[0][i], to[1][i]) is the (lat, lon) coordinate of
   *             the ith point
   * @return the "to" array
   */
  public float[][] projToLatLon(float[][] from, float[][] to) {

    float[] fromX = from[INDEX_X];
    float[] fromY = from[INDEX_Y];
    to[INDEX_LAT] = fromY;
    to[INDEX_LON] = fromX;
    return to;
  }


  /**
   * Convert lat/lon coordinates to projection coordinates.
   *
   * @param from     array of lat/lon coordinates: from[2][n], where
   *                 (from[latIndex][i], from[lonIndex][i]) is the (lat,lon)
   *                 coordinate of the ith point
   * @param to       resulting array of projection coordinates: to[2][n]
   *                 where (to[0][i], to[1][i]) is the (x,y) coordinate of
   *                 the ith point
   * @param latIndex index of lat coordinate; must be 0 or 1
   * @param lonIndex index of lon coordinate; must be 0 or 1
   * @return the "to" array
   */
  public float[][] latLonToProj(float[][] from, float[][] to, int latIndex,
                                int lonIndex) {
    int cnt = from[0].length;
    float[] toX = to[INDEX_X];
    float[] toY = to[INDEX_Y];
    float[] fromLat = from[latIndex];
    float[] fromLon = from[lonIndex];
    float lat, lon;
    for (int i = 0; i < cnt; i++) {
      lat = fromLat[i];
      lon = (float) (centerLon
          + Math.IEEEremainder(fromLon[i] - centerLon,
          360.0));
      toX[i] = lon;
      toY[i] = lat;
    }
    return to;
  }


  /**
   * Convert projection coordinates to lat/lon coordinate.
   *
   * @param from array of projection coordinates: from[2][n], where
   *             (from[0][i], from[1][i]) is the (x, y) coordinate
   *             of the ith point
   * @param to   resulting array of lat/lon coordinates: to[2][n] where
   *             (to[0][i], to[1][i]) is the (lat, lon) coordinate of
   *             the ith point
   * @return the "to" array
   */
  public double[][] projToLatLon(double[][] from, double[][] to) {

    double[] fromX = from[INDEX_X];
    double[] fromY = from[INDEX_Y];
    to[INDEX_LAT] = fromY;
    to[INDEX_LON] = fromX;
    return to;
  }

  /**
   * Convert lat/lon coordinates to projection coordinates.
   *
   * @param from     array of lat/lon coordinates: from[2][n], where
   *                 (from[latIndex][i], from[lonIndex][i]) is the (lat,lon)
   *                 coordinate of the ith point
   * @param to       resulting array of projection coordinates: to[2][n]
   *                 where (to[0][i], to[1][i]) is the (x,y) coordinate of
   *                 the ith point
   * @param latIndex index of lat coordinate; must be 0 or 1
   * @param lonIndex index of lon coordinate; must be 0 or 1
   * @return the "to" array
   */
  public double[][] latLonToProj(double[][] from, double[][] to,
                                 int latIndex, int lonIndex) {
    int cnt = from[0].length;
    double[] toX = to[INDEX_X];
    double[] toY = to[INDEX_Y];
    double[] fromLat = from[latIndex];
    double[] fromLon = from[lonIndex];
    double lat, lon;
    for (int i = 0; i < cnt; i++) {
      lat = fromLat[i];
      lon = centerLon
          + Math.IEEEremainder(fromLon[i] - centerLon, 360.0);
      toX[i] = lon;
      toY[i] = lat;
    }
    return to;
  }


  /**
   * Clone this projection
   *
   * @return a clone of this projection
   */
  public Object clone() {
    LatLonProjection pp = (LatLonProjection) super.clone();
    pp.centerLon = centerLon;
    return pp;
  }


  /**
   * Set the center of the Longitude range. It is normalized to  +/- 180.
   * The cylinder is cut at the "seam" = centerLon +- 180.
   * Use this to keep the Longitude values kept in the range [centerLon +-180], which
   * makes seam handling easier.
   *
   * @param centerLon the center of the Longitude range.
   * @return centerLon normalized to +/- 180.
   */
  public double setCenterLon(double centerLon) {
    this.centerLon = LatLonPointImpl.lonNormal(centerLon);
    return this.centerLon;
  }

  /**
   * Get the center of the Longitude range. It is normalized to  +/- 180.
   *
   * @return the center longitude
   */
  public double getCenterLon() {
    return centerLon;
  }


  /**
   * Does the line between these two points cross the projection "seam".
   *
   * @param pt1 the line goes between these two points
   * @param pt2 the line goes between these two points
   * @return false if there is no seam
   */
  public boolean crossSeam(ProjectionPoint pt1, ProjectionPoint pt2) {
    return Math.abs(pt1.getX() - pt2.getX()) > 270.0;  // ?? LOOK: do I believe this
  }


  /**
   * Set a reasonable bounding box for this projection.
   *
   * @param bb a reasonable bounding box
   */
  public void setDefaultMapArea(ProjectionRect bb) {
    super.setDefaultMapArea(bb);
    this.centerLon = bb.getCenterX();
    // setCenterLon( bb.getCenterX());
  }

  /**
   * Split a latlon rectangle to the equivalent ProjectionRect
   * using this LatLonProjection to split it at the seam if needed.
   *
   * @param latlonR the latlon rectangle to transform
   * @return 1 or 2 ProjectionRect. If it doesnt cross the seam,
   *         the second rectangle is null.
   */
  public ProjectionRect[] latLonToProjRect(LatLonRect latlonR) {

    double lat0 = latlonR.getLowerLeftPoint().getLatitude();
    double height = Math.abs(latlonR.getUpperRightPoint().getLatitude() - lat0);
    double width = latlonR.getWidth();
    double lon0 = LatLonPointImpl.lonNormal(
        latlonR.getLowerLeftPoint().getLongitude(),
        centerLon);
    double lon1 = LatLonPointImpl.lonNormal(
        latlonR.getUpperRightPoint().getLongitude(),
        centerLon);

    if (lon0 < lon1) {
      projR1.setRect(lon0, lat0, width, height);
      rects[0] = projR1;
      rects[1] = null;
    } else {
      double y = centerLon + 180 - lon0;

      projR1.setRect(lon0, lat0, y, height);
      projR2.setRect(lon1 - width + y, lat0, width - y, height);
      rects[0] = projR1;
      rects[1] = projR2;
    }

    return rects;
  }

  public LatLonRect projToLatLonBB(ProjectionRect world) {    
    double startLat = world.getMinY();
    double startLon = world.getMinX();

    double deltaLat = world.getHeight();
    double deltaLon = world.getWidth();

    LatLonPoint llpt = new LatLonPointImpl(startLat, startLon);
    return new LatLonRect(llpt, deltaLat, deltaLon);
  }

  /**
   * projection rect 1
   */
  private ProjectionRect projR1 = new ProjectionRect();

  /**
   * projection rect 1
   */
  private ProjectionRect projR2 = new ProjectionRect();

  /**
   * array fo rects
   */
  private ProjectionRect rects[] = new ProjectionRect[2];

  /**
   * Create a latlon rectangle and split it into the equivalent
   * ProjectionRect using this LatLonProjection. The latlon rect is
   * constructed from 2 lat/lon points. The lon values are considered
   * coords in the latlonProjection, and so do not have to be +/- 180.
   *
   * @param lat0 lat of point 1
   * @param lon0 lon of point 1
   * @param lat1 lat of point 1
   * @param lon1 lon of point 1
   * @return 1 or 2 ProjectionRect. If it doesnt cross the seam,
   *         the second rectangle is null.
   */
  public ProjectionRect[] latLonToProjRect(double lat0, double lon0,
                                           double lat1, double lon1) {

    double height = Math.abs(lat1 - lat0);
    lat0 = Math.min(lat1, lat0);
    double width = lon1 - lon0;
    if (width < 1.0e-8) {
      width = 360.0;  // assume its the whole thing
    }
    lon0 = LatLonPointImpl.lonNormal(lon0, centerLon);
    lon1 = LatLonPointImpl.lonNormal(lon1, centerLon);

    if (width >= 360.0) {
      projR1.setRect(centerLon - 180.0, lat0, 360.0, height);
      rects[0] = projR1;
      rects[1] = null;
    } else if (lon0 < lon1) {
      projR1.setRect(lon0, lat0, width, height);
      rects[0] = projR1;
      rects[1] = null;
    } else {
      double y = centerLon + 180 - lon0;
      projR1.setRect(lon0, lat0, y, height);
      projR2.setRect(lon1 - width + y, lat0, width - y, height);
      rects[0] = projR1;
      rects[1] = projR2;
    }
    return rects;
  }

}

/*
 *  Change History:
 *  $Log: LatLonProjection.java,v $
 *  Revision 1.31  2006/11/18 19:03:22  dmurray
 *  jindent
 *
 *  Revision 1.30  2006/11/16 00:17:02  caron
 *  add FlatEarth projection (used by Nids grids)
 *
 *  Revision 1.29  2006/08/18 17:07:39  dmurray
 *  fix a problem with the projToLatLon and latlonToProj methods that
 *  take arrays.  They were assuming that from and to were different, but
 *  the could be the same to save on memory.
 *
 *  Revision 1.28  2005/05/13 18:29:18  jeffmc
 *  Clean up the odd copyright symbols
 *
 *  Revision 1.27  2005/05/13 12:26:51  jeffmc
 *  Some mods
 *
 *  Revision 1.26  2005/05/13 11:14:10  jeffmc
 *  Snapshot
 *
 *  Revision 1.25  2004/09/22 21:19:52  caron
 *  use Parameter, not Attribute; remove nc2 dependencies
 *
 *  Revision 1.24  2004/07/30 17:22:20  dmurray
 *  Jindent and doclint
 *
 *  Revision 1.23  2004/02/27 21:21:40  jeffmc
 *  Lots of javadoc warning fixes
 *
 *  Revision 1.22  2004/01/29 17:35:00  jeffmc
 *  A big sweeping checkin after a big sweeping reformatting
 *  using the new jindent.
 *
 *  jindent adds in javadoc templates and reformats existing javadocs. In the new javadoc
 *  templates there is a '_more_' to remind us to fill these in.
 *
 *  Revision 1.21  2003/07/12 23:08:59  caron
 *  add cvs headers, trailers
 *
 */




© 2015 - 2025 Weber Informatics LLC | Privacy Policy