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

ucar.unidata.geoloc.ProjectionImpl 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.unidata.geoloc.projection.LatLonProjection;
import ucar.unidata.util.*;

import java.util.*;

/**
 * Superclass for our implementations of geoloc.Projection.
 * 

*

All subclasses must:

    *
  • override equals() and return true when all parameters are equal *
  • create "atts" list of parameters as string-valued Attribute pairs *
  • implement abstract methods *
*

* If possible, set defaultmapArea to some reasonable world coord bounding box * otherwise, provide a way for the user to specify it when a specific projection * is created. *

*

Note on "false_easting" and "fale_northing" projection parameters: *

  • false_easting(northing) = The value added to all x (y) values in the rectangular coordinates for a map projection. * This value frequently is assigned to eliminate negative numbers. * Expressed in the unit of measure identified in Planar Coordinate Units. *
  • We dont currently use, assuming that the x and y are just fine as negetive numbers. *
* * @author John Caron * @see Projection */ public abstract class ProjectionImpl implements Projection, java.io.Serializable { /** * Earth radius in kilometers */ static public final double EARTH_RADIUS = Earth.getRadius() * 0.001; // km /** * Latitude index */ public static final int INDEX_LAT = 0; /** * Longitude index */ public static final int INDEX_LON = 1; /** * X index */ public static final int INDEX_X = 0; /** * Y index */ public static final int INDEX_Y = 1; /** * tolerence for checks */ protected static final double TOLERANCE = 1.0e-6; /** * PI */ public static final double PI = Math.PI; /** * PI/2 */ public static final double PI_OVER_2 = Math.PI / 2.0; /** * PI/4 */ public static final double PI_OVER_4 = Math.PI / 4.0; /////////////////////////////////////////////////////////////////////// /** * name of this projection. */ protected String name; // LOOK should be final, IDV needs setName() /** * flag for latlon */ protected final boolean isLatLon; /** * list of attributes */ protected final List atts = new ArrayList<>(); /** * default map area */ protected ProjectionRect defaultMapArea = new ProjectionRect(); /** * copy constructor - avoid clone !! * * @return a copy of this Projection */ abstract public ProjectionImpl constructCopy(); protected ProjectionImpl(String name, boolean isLatLon) { this.name = name; this.isLatLon = isLatLon; } /** * Get the name of the type of the projection. * * @return the class name */ public String getClassName() { String className = getClass().getName(); int index = className.lastIndexOf("."); if (index >= 0) { className = className.substring(index + 1); } return className; } /** * Get a string representation of the projection parameters * * @return string representation of the projection parameters */ public abstract String paramsToString(); /** * Get the label to be used in the gui for this type of projection. * This defaults to call getClassName * * @return Type label */ public String getProjectionTypeLabel() { return getClassName(); } /** * Convert a LatLonPoint to projection coordinates * * @param latlon convert from these lat, lon coordinates * @param destPoint the object to write to * @return the given destPoint */ public abstract ProjectionPoint latLonToProj(LatLonPoint latlon, ProjectionPointImpl destPoint); /** * Convert projection coordinates to a LatLonPoint * Note: a new object is not created on each call for the return value. * * @param ppt convert from these projection coordinates * @param destPoint the object to write to * @return LatLonPoint convert to these lat/lon coordinates */ public abstract LatLonPoint projToLatLon(ProjectionPoint ppt, LatLonPointImpl destPoint); /** * Convert a LatLonPoint to projection coordinates * Note: a new object is now created on each call for the return value, as of 4.0.46 * * @param latLon convert from these lat, lon coordinates * @return ProjectionPoint convert to these projection coordinates */ public ProjectionPoint latLonToProj(LatLonPoint latLon) { return latLonToProj(latLon, new ProjectionPointImpl()); } /** * Convert projection coordinates to a LatLonPoint * Note: a new object is now created on each call for the return value, as of 4.0.46 * * @param ppt convert from these projection coordinates * @return LatLonPoint convert to these lat/lon coordinates */ public LatLonPoint projToLatLon(ProjectionPoint ppt) { return projToLatLon(ppt, new LatLonPointImpl()); } /** * 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 abstract boolean crossSeam(ProjectionPoint pt1, ProjectionPoint pt2); /** * Returns true if this represents the same Projection as proj. * * @param proj projection in question * @return true if this represents the same Projection as proj. */ public abstract boolean equals(Object proj); /** * Get the name of this specific projection (also see getClassName) * * @return name of the projection */ public String getName() { return name; } public void setName(String name) { this.name = name; } /** * Get parameters as list of ucar.unidata.util.Parameter * * @return List of parameters */ public List getProjectionParameters() { return atts; } public Parameter findProjectionParameter(String want) { for (Parameter p : atts) { if (p.getName().equals(want)) return p; } return null; } /** * Add an attribute to this projection * * @param name name of the attribute * @param value attribute value as a string */ protected void addParameter(String name, String value) { atts.add(new Parameter(name, value)); } /** * Add an attribute to this projection * * @param name name of the attribute * @param value attribute value as a double */ protected void addParameter(String name, double value) { atts.add(new Parameter(name, value)); } /** * Add an attribute to this projection * * @param p specify as a Parameter */ protected void addParameter(Parameter p) { atts.add(p); } /** * Is this the lat/lon Projection ? * * @return true if it is the lat/lon Projection */ public boolean isLatLon() { return isLatLon; } /** * Get a header for display. * * @return human readable header for display */ public static String getHeader() { StringBuilder headerB = new StringBuilder(60); headerB.append("Name"); Format.tab(headerB, 20, true); headerB.append("Class"); Format.tab(headerB, 40, true); headerB.append("Parameters"); return headerB.toString(); } /** * Get a String representation of this projection. * * @return the name of the projection. This is what gets * displayed when you add the projection object to * a UI widget (e.g. label, combobox) */ public String toString() { return getName(); } /** * Get a reasonable bounding box for this projection. * * @return reasonable bounding box */ public ProjectionRect getDefaultMapArea() { return defaultMapArea; } /** * Get the bounding box in lat/lon. * * @return the LatLonRectangle for the bounding box */ public LatLonRect getDefaultMapAreaLL() { return projToLatLonBB(defaultMapArea); } /** * Set a reasonable bounding box for this specific projection. * Projections are typically specific to an area of the world; * theres no bounding box that works for all projections. * * @param bb bounding box */ public void setDefaultMapArea(ProjectionRect bb) { if (bb == null) return; defaultMapArea = new ProjectionRect(bb); } //////// convenience routines /** * Convert a LatLonPoint to projection coordinates * Note: a new object is now created on each call for the return value, as of 4.0.46 * * @param lat latitude of point to convert * @param lon longitude of point to convert * @return ProjectionPointImpl convert to these projection coordinates */ public ProjectionPoint latLonToProj(double lat, double lon) { return latLonToProj(new LatLonPointImpl(lat, lon)); } /** * Convert a projection coordinate to a LatLonPoint * Note: a new object is now created on each call for the return value, as of 4.0.46 * * @param x x value to convert * @param y y value to convert * @return LatLonPointImpl convert to these lat/lon coordinates */ public LatLonPoint projToLatLon(double x, double y) { return projToLatLon(new ProjectionPointImpl(x, y)); } /////////////////////////////////////////////////////////////////////////////////// // optimizations for doing double and float arrays /** * Convert projection coordinates to lat/lon coordinates. * * @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 * @return resulting array of lat/lon coordinates, where to[0][i], to[1][i] * is the lat,lon coordinate of the ith point */ public double[][] projToLatLon(double[][] from) { return projToLatLon(from, new double[2][from[0].length]); } /** * 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) { if ((from == null) || (from.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "null array argument or wrong dimension (from)"); } if ((to == null) || (to.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "null array argument or wrong dimension (to)"); } if (from[0].length != to[0].length) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "from array not same length as to array"); } for (int i = 0; i < from[0].length; i++) { LatLonPoint endL = projToLatLon(from[0][i], from[1][i]); to[0][i] = endL.getLatitude(); to[1][i] = endL.getLongitude(); } return to; } /** * Convert projection coordinates to lat/lon coordinates. * * @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 * @return resulting array of lat/lon coordinates, where to[0][i], to[1][i] * is the lat,lon coordinate of the ith point */ public float[][] projToLatLon(float[][] from) { return projToLatLon(from, new float[2][from[0].length]); } /** * 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) { if ((from == null) || (from.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "null array argument or wrong dimension (from)"); } if ((to == null) || (to.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "null array argument or wrong dimension (to)"); } if (from[0].length != to[0].length) { throw new IllegalArgumentException("ProjectionImpl.projToLatLon:" + "from array not same length as to array"); } ProjectionPointImpl ppi = new ProjectionPointImpl(); LatLonPointImpl llpi = new LatLonPointImpl(); for (int i = 0; i < from[0].length; i++) { ppi.setLocation((double) from[0][i], (double) from[1][i]); projToLatLon(ppi, llpi); to[0][i] = (float) llpi.getLatitude(); to[1][i] = (float) llpi.getLongitude(); } 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 * @return resulting array of projection coordinates, where to[0][i], * to[1][i] is the (x,y) coordinate of the ith point */ public double[][] latLonToProj(double[][] from) { return latLonToProj(from, new double[2][from[0].length]); } /** * 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[][] latLonToProj(double[][] from, double[][] to) { return latLonToProj(from, to, INDEX_LAT, INDEX_LON); } /** * 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 latIndex index of lat coordinate; must be 0 or 1 * @param lonIndex index of lon coordinate; must be 0 or 1 * @return resulting array of projection coordinates: to[2][n] where * (to[0][i], to[1][i]) is the (x,y) coordinate of the ith point */ public double[][] latLonToProj(double[][] from, int latIndex, int lonIndex) { return latLonToProj(from, new double[2][from[0].length], latIndex, lonIndex); } /** * 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) { if ((from == null) || (from.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "null array argument or wrong dimension (from)"); } if ((to == null) || (to.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "null array argument or wrong dimension (to)"); } if (from[0].length != to[0].length) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "from array not same length as to array"); } ProjectionPointImpl ppi = new ProjectionPointImpl(); LatLonPointImpl llpi = new LatLonPointImpl(); for (int i = 0; i < from[0].length; i++) { llpi.setLatitude(from[latIndex][i]); llpi.setLongitude(from[lonIndex][i]); latLonToProj(llpi, ppi); to[0][i] = ppi.getX(); to[1][i] = ppi.getY(); } 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 * @return resulting array of projection coordinates, where to[0][i], * to[1][i] is the (x,y) coordinate of the ith point */ public float[][] latLonToProj(float[][] from) { return latLonToProj(from, new float[2][from[0].length]); } /** * 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[][] latLonToProj(float[][] from, float[][] to) { return latLonToProj(from, to, INDEX_LAT, INDEX_LON); } /** * 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 latIndex index of lat coordinate; must be 0 or 1 * @param lonIndex index of lon coordinate; must be 0 or 1 * @return resulting array of projection coordinates: to[2][n] where * (to[0][i], to[1][i]) is the (x,y) coordinate of the ith point */ public float[][] latLonToProj(float[][] from, int latIndex, int lonIndex) { return latLonToProj(from, new float[2][from[0].length], latIndex, lonIndex); } /** * 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) { // ucar.unidata.util.Misc.printStack ("latLonToProj-" + this + " size=" + from[0].length, 4, null); if ((from == null) || (from.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "null array argument or wrong dimension (from)"); } if ((to == null) || (to.length != 2)) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "null array argument or wrong dimension (to)"); } if (from[0].length != to[0].length) { throw new IllegalArgumentException("ProjectionImpl.latLonToProj:" + "from array not same length as to array"); } ProjectionPointImpl ppi = new ProjectionPointImpl(); LatLonPointImpl llpi = new LatLonPointImpl(); for (int i = 0; i < from[0].length; i++) { llpi.setLatitude(from[latIndex][i]); llpi.setLongitude(from[lonIndex][i]); latLonToProj(llpi, ppi); to[0][i] = (float) ppi.getX(); to[1][i] = (float) ppi.getY(); } return to; } // bounding box utilities /** * Alternate way to calculate latLonToProjBB, originally in GridCoordSys. * Difficult to do this in a general way. * * @param latlonRect desired lat/lon rectangle * @return a ProjectionRect */ ProjectionRect latLonToProjBB2(LatLonRect latlonRect) { double minx, maxx, miny, maxy; LatLonPointImpl llpt = latlonRect.getLowerLeftPoint(); LatLonPointImpl urpt = latlonRect.getUpperRightPoint(); LatLonPointImpl lrpt = latlonRect.getLowerRightPoint(); LatLonPointImpl ulpt = latlonRect.getUpperLeftPoint(); if (isLatLon()) { minx = getMinOrMaxLon(llpt.getLongitude(), ulpt.getLongitude(), true); miny = Math.min(llpt.getLatitude(), lrpt.getLatitude()); maxx = getMinOrMaxLon(urpt.getLongitude(), lrpt.getLongitude(), false); maxy = Math.min(ulpt.getLatitude(), urpt.getLatitude()); } else { ProjectionPoint ll = latLonToProj(llpt, new ProjectionPointImpl()); ProjectionPoint ur = latLonToProj(urpt, new ProjectionPointImpl()); ProjectionPoint lr = latLonToProj(lrpt, new ProjectionPointImpl()); ProjectionPoint ul = latLonToProj(ulpt, new ProjectionPointImpl()); minx = Math.min(ll.getX(), ul.getX()); miny = Math.min(ll.getY(), lr.getY()); maxx = Math.max(ur.getX(), lr.getX()); maxy = Math.max(ul.getY(), ur.getY()); } return new ProjectionRect(minx, miny, maxx, maxy); } private double getMinOrMaxLon(double lon1, double lon2, boolean wantMin) { double midpoint = (lon1 + lon2) / 2; lon1 = LatLonPointImpl.lonNormal(lon1, midpoint); lon2 = LatLonPointImpl.lonNormal(lon2, midpoint); return wantMin ? Math.min(lon1, lon2) : Math.max(lon1, lon2); } /** * Convert a lat/lon bounding box to a world coordinate bounding box, * by finding the minimum enclosing box. * Handles lat/lon points that do not intersect the projection panel. * * @param latlonRect input lat,lon bounding box * @return minimum enclosing box in world coordinates, or null if no part of the LatLonRect intersects the projection plane */ public ProjectionRect latLonToProjBB(LatLonRect latlonRect) { if (isLatLon) { LatLonProjection llp = (LatLonProjection) this; llp.setCenterLon(latlonRect.getCenterLon()); // LOOK side effect BAD !! } ProjectionPointImpl w1 = new ProjectionPointImpl(); ProjectionPointImpl w2 = new ProjectionPointImpl(); LatLonPoint ll = latlonRect.getLowerLeftPoint(); LatLonPoint ur = latlonRect.getUpperRightPoint(); latLonToProj(ll, w1); latLonToProj(ur, w2); //if (!isLatLon && crossSeam(w1, w2)) { // log.warn("CROSS SEAM failure=" + w1 + " " + w2+" for "+this, new Throwable()); //} // make bounding box out of those two corners ProjectionRect world = new ProjectionRect(w1.getX(), w1.getY(), w2.getX(), w2.getY()); LatLonPointImpl la = new LatLonPointImpl(); LatLonPointImpl lb = new LatLonPointImpl(); // now extend if needed to the other two corners la.setLatitude(ur.getLatitude()); la.setLongitude(ll.getLongitude()); latLonToProj(la, w1); world.add(w1); lb.setLatitude(ll.getLatitude()); lb.setLongitude(ur.getLongitude()); latLonToProj(lb, w2); world.add(w2); return world; } /** * Convert a world coordinate bounding box to a lat/lon bounding box, * by finding the minimum enclosing box. * * @param world input world coordinate bounding box * @return minimum enclosing box in lat,lon coordinates. */ public LatLonRect projToLatLonBBold(ProjectionRect world) { //System.out.println("world = " + world); ProjectionPoint min = world.getMinPoint(); ProjectionPoint max = world.getMaxPoint(); //System.out.println("min = " + min); //System.out.println("max = " + max); LatLonRect llbb; LatLonPointImpl llmin = new LatLonPointImpl(); LatLonPointImpl llmax = new LatLonPointImpl(); // make bounding box out of the min, max corners projToLatLon(min, llmin); projToLatLon(max, llmax); llbb = new LatLonRect(llmin, llmax); //System.out.println("llbb = " + llbb); /* double lona = la.getLongitude(); double lonb = lb.getLongitude(); if (((lona < lonb) && (lonb - lona <= 180.0)) || ((lona > lonb) && (lona - lonb >= 180.0))) { llbb = new LatLonRect(la, lb); } else { llbb = new LatLonRect(lb, la); } */ ProjectionPointImpl w1 = new ProjectionPointImpl(); ProjectionPointImpl w2 = new ProjectionPointImpl(); // now extend if needed using the other two corners w1.setLocation(min.getX(), max.getY()); projToLatLon(w1, llmin); llbb.extend(llmin); w2.setLocation(max.getX(), min.getY()); projToLatLon(w2, llmax); llbb.extend(llmax); return llbb; } /** * Compute lat/lon bounding box from projection bounding box by finding the minimum enclosing box. * @param bb projection bounding box * @return lat, lon bounding box. */ public LatLonRect projToLatLonBB(ProjectionRect bb) { // look at all 4 corners of the bounding box LatLonPoint llpt = projToLatLon(bb.getLowerLeftPoint(), new LatLonPointImpl()); LatLonPoint lrpt = projToLatLon(bb.getLowerRightPoint(), new LatLonPointImpl()); LatLonPoint urpt = projToLatLon(bb.getUpperRightPoint(), new LatLonPointImpl()); LatLonPoint ulpt = projToLatLon(bb.getUpperLeftPoint(), new LatLonPointImpl()); // Check if grid contains poles. boolean includesNorthPole = false; /* int[] resultNP; findXYindexFromLatLon(90.0, 0, resultNP); if (resultNP[0] != -1 && resultNP[1] != -1) includesNorthPole = true; */ boolean includesSouthPole = false; /* int[] resultSP = new int[2]; findXYindexFromLatLon(-90.0, 0, resultSP); if (resultSP[0] != -1 && resultSP[1] != -1) includesSouthPole = true; */ LatLonRect llbb; if (includesNorthPole && !includesSouthPole) { llbb = new LatLonRect(llpt, new LatLonPointImpl(90.0, 0.0)); // ??? lon=??? llbb.extend(lrpt); llbb.extend(urpt); llbb.extend(ulpt); // OR //llbb.extend( new LatLonRect( llpt, lrpt )); //llbb.extend( new LatLonRect( lrpt, urpt ) ); //llbb.extend( new LatLonRect( urpt, ulpt ) ); //llbb.extend( new LatLonRect( ulpt, llpt ) ); } else if (includesSouthPole && !includesNorthPole) { llbb = new LatLonRect(llpt, new LatLonPointImpl(-90.0, -180.0)); // ??? lon=??? llbb.extend(lrpt); llbb.extend(urpt); llbb.extend(ulpt); } else { double latMin = Math.min(llpt.getLatitude(), lrpt.getLatitude()); double latMax = Math.max(ulpt.getLatitude(), urpt.getLatitude()); // longitude is a bit tricky as usual double lonMin = getMinOrMaxLon(llpt.getLongitude(), ulpt.getLongitude(), true); double lonMax = getMinOrMaxLon(lrpt.getLongitude(), urpt.getLongitude(), false); LatLonPointImpl min = new LatLonPointImpl(latMin, lonMin); LatLonPointImpl max = new LatLonPointImpl(latMax, lonMax); llbb = new LatLonRect(min, max); } return llbb; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy