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

ucar.unidata.geoloc.projection.FlatEarth 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.projection;


import ucar.nc2.constants.CF;
import ucar.unidata.geoloc.*;


/**
 * FlatEarth Projection
 * This projection surface is tangent at some point (lat0, lon0) and
 * has a y axis rotated from true North by some angle.
 * 

* We call it "flat" because it should only be used where the spherical * geometry of the earth is not significant. In actuallity, we use the simple * "arclen" routine which computes dy along a meridian, and dx along a * latitude circle. We rotate the coordinate system to/from a true north system. *

* See John Snyder, Map Projections used by the USGS, Bulletin 1532, * 2nd edition (1983), p 145 * * @author Unidata Development Team * @see Projection * @see ProjectionImpl */ public class FlatEarth extends ProjectionImpl { public static final String ROTATIONANGLE = "rotationAngle"; /** * constants from Snyder's equations */ private final double rotAngle, radius; private final double lat0, lon0; // center lat/lon in radians /** * some constants */ private double cosRot, sinRot; /** * origin */ //private LatLonPointImpl origin; // why are we keeping this? @Override public ProjectionImpl constructCopy() { ProjectionImpl result = new FlatEarth(getOriginLat(), getOriginLon(), getRotationAngle()); result.setDefaultMapArea(defaultMapArea); result.setName(name); return result; } /** * Constructor with default parameters */ public FlatEarth() { this(0.0, 0.0, 0.0, EARTH_RADIUS); } public FlatEarth(double lat0, double lon0) { this(lat0, lon0, 0.0, EARTH_RADIUS); } public FlatEarth(double lat0, double lon0, double rotAngle) { this(lat0, lon0, rotAngle, EARTH_RADIUS); } /** * Construct a FlatEarth Projection, two standard parellels. * For the one standard parellel case, set them both to the same value. * * @param lat0 lat origin of the coord. system on the projection plane * @param lon0 lon origin of the coord. system on the projection plane * @param rotAngle angle of rotation, in degrees * @param radius earth radius in km * @throws IllegalArgumentException if lat0, par1, par2 = +/-90 deg */ public FlatEarth(double lat0, double lon0, double rotAngle, double radius) { super("FlatEarth", false); this.lat0 = Math.toRadians(lat0); this.lon0 = Math.toRadians(lon0); this.rotAngle = Math.toRadians(rotAngle); this.radius = radius; precalculate(); addParameter(CF.GRID_MAPPING_NAME, "flat_earth"); addParameter(CF.LATITUDE_OF_PROJECTION_ORIGIN, lat0); addParameter(CF.LONGITUDE_OF_PROJECTION_ORIGIN, lon0); addParameter(ROTATIONANGLE, rotAngle); addParameter(CF.EARTH_RADIUS, radius * 1000); } /** * Precalculate some stuff */ private void precalculate() { sinRot = Math.sin(rotAngle); cosRot = Math.cos(rotAngle); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FlatEarth flatEarth = (FlatEarth) o; if (Double.compare(flatEarth.lat0, lat0) != 0) return false; if (Double.compare(flatEarth.lon0, lon0) != 0) return false; if (Double.compare(flatEarth.radius, radius) != 0) return false; if (Double.compare(flatEarth.rotAngle, rotAngle) != 0) return false; if ((defaultMapArea == null) != (flatEarth.defaultMapArea == null)) return false; // common case is that these are null if (defaultMapArea != null && !flatEarth.defaultMapArea.equals(defaultMapArea)) return false; return true; } @Override public int hashCode() { int result; long temp; temp = rotAngle != +0.0d ? Double.doubleToLongBits(rotAngle) : 0L; result = (int) (temp ^ (temp >>> 32)); temp = radius != +0.0d ? Double.doubleToLongBits(radius) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = lat0 != +0.0d ? Double.doubleToLongBits(lat0) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = lon0 != +0.0d ? Double.doubleToLongBits(lon0) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } // bean properties /** * Get the origin longitude. * * @return the origin longitude. */ public double getOriginLon() { return Math.toDegrees(lon0); } /** * Get the origin latitude. * * @return the origin latitude. */ public double getOriginLat() { return Math.toDegrees(lat0); } /** * Get the rotation angle. * * @return the origin latitude. */ public double getRotationAngle() { return rotAngle; } /** * Get the label to be used in the gui for this type of projection * * @return Type label */ public String getProjectionTypeLabel() { return "FlatEarth"; } /** * Create a String of the parameters. * * @return a String of the parameters */ public String paramsToString() { return toString(); } @Override public String toString() { return "FlatEarth{" + "rotAngle=" + rotAngle + ", radius=" + radius + ", lat0=" + lat0 + ", lon0=" + lon0 + '}'; } /** * 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) { double toX, toY; double fromLat = latLon.getLatitude(); double fromLon = latLon.getLongitude(); double dx, dy; fromLat = Math.toRadians(fromLat); dy = radius * (fromLat - lat0); dx = radius * Math.cos(fromLat) * (Math.toRadians(fromLon) - lon0); toX = cosRot * dx - sinRot * dy; toY = sinRot * dx + cosRot * dy; result.setLocation(toX, toY); 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) { double toLat, toLon; double x = world.getX(); double y = world.getY(); double cosl; int TOLERENCE = 1; double xp, yp; xp = cosRot * x + sinRot * y; yp = -sinRot * x + cosRot * y; toLat = Math.toDegrees(lat0) + Math.toDegrees(yp / radius); //double lat2; //lat2 = lat0 + Math.toDegrees(yp/radius); cosl = Math.cos(Math.toRadians(toLat)); if (Math.abs(cosl) < TOLERANCE) { toLon = Math.toDegrees(lon0); } else { toLon = Math.toDegrees(lon0) + Math.toDegrees(xp / cosl / radius); } toLon = LatLonPointImpl.lonNormal(toLon); result.setLatitude(toLat); result.setLongitude(toLon); return result; } /** * Convert lat/lon coordinates to projection coordinates. * * @param from array of lat/lon coordinates: from[2][n], * where from[0][i], from[1][i] is the (lat,lon) * coordinate of the ith point * @param to resulting array of projection coordinates, * where to[0][i], to[1][i] is the (x,y) coordinate * of the ith point * @param latIndex index of latitude in "from" * @param lonIndex index of longitude in "from" * @return the "to" array. */ public float[][] latLonToProj(float[][] from, float[][] to, int latIndex, int lonIndex) { int cnt = from[0].length; float[] fromLatA = from[latIndex]; float[] fromLonA = from[lonIndex]; float[] resultXA = to[INDEX_X]; float[] resultYA = to[INDEX_Y]; double toX, toY; for (int i = 0; i < cnt; i++) { double fromLat = fromLatA[i]; double fromLon = fromLonA[i]; fromLat = Math.toRadians(fromLat); double dy = radius * (fromLat - lat0); double dx = radius * Math.cos(fromLat) * (Math.toRadians(fromLon) - lon0); toX = cosRot * dx - sinRot * dy; toY = sinRot * dx + cosRot * dy; resultXA[i] = (float) toX; resultYA[i] = (float) toY; } return to; } /** * This returns true when the line between pt1 and pt2 crosses the seam. * When the cone is flattened, the "seam" is lon0 +- 180. * * @param pt1 point 1 * @param pt2 point 2 * @return true when the line between pt1 and pt2 crosses the seam. */ public boolean crossSeam(ProjectionPoint pt1, ProjectionPoint pt2) { return (pt1.getX() * pt2.getX() < 0); } /** * Convert lat/lon coordinates to projection coordinates. * * @param from array of lat/lon coordinates: from[2][n], where * (from[0][i], from[1][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 * @return the "to" array */ public float[][] projToLatLon(float[][] from, float[][] to) { int cnt = from[0].length; float[] fromXA = from[INDEX_X]; float[] fromYA = from[INDEX_Y]; float[] toLatA = to[INDEX_LAT]; float[] toLonA = to[INDEX_LON]; double toLat, toLon; for (int i = 0; i < cnt; i++) { double fromX = fromXA[i]; double fromY = fromYA[i]; double xp = cosRot * fromX + sinRot * fromY; double yp = -sinRot * fromX + cosRot * fromY; toLat = Math.toDegrees(lat0) + Math.toDegrees(yp / radius); double cosl = Math.cos(Math.toRadians(toLat)); if (Math.abs(cosl) < TOLERANCE) { toLon = Math.toDegrees(lon0); } else { toLon = Math.toDegrees(lon0) + Math.toDegrees(xp / cosl / radius); } toLon = LatLonPointImpl.lonNormal(toLon); toLatA[i] = (float) toLat; toLonA[i] = (float) toLon; } return to; } /** * Convert lat/lon coordinates to projection coordinates. * * @param from array of lat/lon coordinates: from[2][n], * where from[0][i], from[1][i] is the (lat,lon) * coordinate of the ith point * @param to resulting array of projection coordinates, * where to[0][i], to[1][i] is the (x,y) coordinate * of the ith point * @param latIndex index of latitude in "from" * @param lonIndex index of longitude in "from" * @return the "to" array. */ public double[][] latLonToProj(double[][] from, double[][] to, int latIndex, int lonIndex) { int cnt = from[0].length; double[] fromLatA = from[latIndex]; double[] fromLonA = from[lonIndex]; double[] resultXA = to[INDEX_X]; double[] resultYA = to[INDEX_Y]; double toX, toY; for (int i = 0; i < cnt; i++) { double fromLat = fromLatA[i]; double fromLon = fromLonA[i]; fromLat = Math.toRadians(fromLat); double dy = radius * (fromLat - lat0); double dx = radius * Math.cos(fromLat) * (Math.toRadians(fromLon) - lon0); toX = cosRot * dx - sinRot * dy; toY = sinRot * dx + cosRot * dy; resultXA[i] = toX; resultYA[i] = toY; } return to; } /** * Convert lat/lon coordinates to projection coordinates. * * @param from array of lat/lon coordinates: from[2][n], where * (from[0][i], from[1][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 * @return the "to" array */ public double[][] projToLatLon(double[][] from, double[][] to) { int cnt = from[0].length; double[] fromXA = from[INDEX_X]; double[] fromYA = from[INDEX_Y]; double[] toLatA = to[INDEX_LAT]; double[] toLonA = to[INDEX_LON]; double toLat, toLon; for (int i = 0; i < cnt; i++) { double fromX = fromXA[i]; double fromY = fromYA[i]; double xp = cosRot * fromX + sinRot * fromY; double yp = -sinRot * fromX + cosRot * fromY; //toLat = lat0 + Math.toDegrees(yp); toLat = Math.toDegrees(lat0) + Math.toDegrees(yp / radius); double cosl = Math.cos(Math.toRadians(toLat)); if (Math.abs(cosl) < TOLERANCE) { toLon = Math.toDegrees(lon0); } else { toLon = Math.toDegrees(lon0) + Math.toDegrees(xp / cosl / radius); } toLon = LatLonPointImpl.lonNormal(toLon); toLatA[i] = toLat; toLonA[i] = toLon; } return to; } /*ENDGENERATED*/ /** * Test * * @param args not used */ public static void main(String[] args) { FlatEarth a = new FlatEarth(90, -100, 0.0); ProjectionPoint p = a.latLonToProj(89, -101); System.out.println("proj point = " + p); LatLonPoint ll = a.projToLatLon(p); System.out.println("ll = " + ll); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy