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

ucar.nc2.dt.grid.GridCoordSys Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998-2018 John Caron and University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */
package ucar.nc2.dt.grid;

import ucar.nc2.*;
import ucar.nc2.constants.AxisType;
import ucar.nc2.constants._Coordinate;
import ucar.nc2.dataset.*;
import ucar.nc2.time.CalendarDate;
import ucar.nc2.time.CalendarDateRange;
import ucar.nc2.util.NamedObject;
import ucar.nc2.units.*;

import ucar.unidata.geoloc.*;
import ucar.unidata.geoloc.projection.LatLonProjection;
import ucar.unidata.geoloc.projection.VerticalPerspectiveView;
import ucar.unidata.geoloc.projection.RotatedPole;
import ucar.unidata.geoloc.projection.RotatedLatLon;
import ucar.unidata.geoloc.projection.sat.MSGnavigation;
import ucar.unidata.geoloc.projection.sat.Geostationary;
import ucar.unidata.geoloc.vertical.*;
import ucar.ma2.*;

import java.util.*;
import java.io.IOException;

import ucar.nc2.units.DateRange;

/**
 * A georeferencing "gridded" CoordinateSystem. This describes a "grid" of coordinates, which
 * implies a connected topology such that values next to each other in index space are next to
 * each other in coordinate space.
 * 

* This currently assumes that the CoordinateSystem *

    *
  1. is georeferencing (has Lat, Lon or GeoX, GeoY axes) *
  2. x, y are 1 or 2-dimensional axes. *
  3. rt, z, e are 1-dimensional axes. *
  4. t is 1 or 2 dimensional. if 2d, then rt exists *
*

* This is the common case for georeferencing coordinate systems. Mathematically it is a product set: * {X,Y} x {Z} x {T}. The x and y axes may be 1 or 2 dimensional. *

*

* A CoordinateSystem may have multiple horizontal and vertical axes. GridCoordSys chooses one * axis corresponding to X, Y, Z, and T. It gives preference to one dimensional axes (CoordinateAxis1D). * * @author caron */ public class GridCoordSys extends CoordinateSystem implements ucar.nc2.dt.GridCoordSystem { static private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GridCoordSys.class); static private final boolean warnUnits = false; /** * Determine if this CoordinateSystem can be made into a GridCoordSys. Optionally for a given variable. * This currently assumes that the CoordinateSystem: *

    *
  1. is georeferencing (cs.isGeoReferencing()) *
  2. x, y are 1 or 2-dimensional axes. *
  3. z, t, if they exist, are 1-dimensional axes. *
  4. domain rank > 1 *
* * @param sbuff place information messages here, may be null * @param cs the CoordinateSystem to test * @param v can it be used for this variable; v may be null * @return true if it can be made into a GridCoordSys. * @see CoordinateSystem#isGeoReferencing */ public static boolean isGridCoordSys(Formatter sbuff, CoordinateSystem cs, VariableEnhanced v) { // must be at least 2 axes if (cs.getRankDomain() < 2) { if (sbuff != null) { sbuff.format("%s: domain rank < 2%n", cs.getName()); } return false; } // must be lat/lon or have x,y and projecction if (!cs.isLatLon()) { // do check for GeoXY ourself if ((cs.getXaxis() == null) || (cs.getYaxis() == null)) { if (sbuff != null) { sbuff.format("%s: NO Lat,Lon or X,Y axis%n", cs.getName()); } return false; } if (null == cs.getProjection()) { if (sbuff != null) { sbuff.format("%s: NO projection found%n", cs.getName()); } return false; } } // obtain the x,y or lat/lon axes. x,y normally must be convertible to km CoordinateAxis xaxis, yaxis; if (cs.isGeoXY()) { xaxis = cs.getXaxis(); yaxis = cs.getYaxis(); // change to warning ProjectionImpl p = cs.getProjection(); if (!(p instanceof RotatedPole)) { if (!SimpleUnit.kmUnit.isCompatible(xaxis.getUnitsString())) { if (sbuff != null) { sbuff.format("%s: X axis units are not convertible to km%n", cs.getName()); } //return false; } if (!SimpleUnit.kmUnit.isCompatible(yaxis.getUnitsString())) { if (sbuff != null) { sbuff.format("%s: Y axis units are not convertible to km%n", cs.getName()); } //return false; } } } else { xaxis = cs.getLonAxis(); yaxis = cs.getLatAxis(); } // check x,y rank <= 2 if ((xaxis.getRank() > 2) || (yaxis.getRank() > 2)) { if (sbuff != null) sbuff.format("%s: X or Y axis rank must be <= 2%n", cs.getName()); return false; } // check that the x,y have at least 2 dimensions between them ( this eliminates point data) int xyDomainSize = CoordinateSystem.countDomain(new CoordinateAxis[]{xaxis, yaxis}); if (xyDomainSize < 2) { if (sbuff != null) sbuff.format("%s: X and Y axis must have 2 or more dimensions%n", cs.getName()); return false; } List testAxis = new ArrayList<>(); testAxis.add(xaxis); testAxis.add(yaxis); //int countRangeRank = 2; CoordinateAxis z = cs.getHeightAxis(); if ((z == null) || !(z instanceof CoordinateAxis1D)) z = cs.getPressureAxis(); if ((z == null) || !(z instanceof CoordinateAxis1D)) z = cs.getZaxis(); if ((z != null) && !(z instanceof CoordinateAxis1D)) { if (sbuff != null) { sbuff.format("%s: Z axis must be 1D%n", cs.getName()); } return false; } if (z != null) testAxis.add(z); // tom margolis 3/2/2010 // allow runtime independent of time CoordinateAxis t = cs.getTaxis(); CoordinateAxis rt = cs.findAxis(AxisType.RunTime); // A runtime axis must be scalar or one-dimensional if (rt != null) { if (!rt.isScalar() && !(rt instanceof CoordinateAxis1D)) { if (sbuff != null) sbuff.format("%s: RunTime axis must be 1D%n", cs.getName()); return false; } } // If time axis is two-dimensional... if ((t != null) && !(t instanceof CoordinateAxis1D) && (t.getRank() != 0)) { if (rt != null) { if (rt.getRank() != 1) { if (sbuff != null) sbuff.format("%s: Runtime axis must be 1D%n", cs.getName()); return false; } // time first dimension must agree with runtime if (!rt.getDimension(0).equals(t.getDimension(0))) { if (sbuff != null) sbuff.format("%s: 2D Time axis first dimension must be runtime%n", cs.getName()); return false; } } } if (t != null) testAxis.add(t); if (rt != null) testAxis.add(rt); CoordinateAxis ens = cs.getEnsembleAxis(); if (ens != null) testAxis.add(ens); if (v != null) { // test to see that v doesnt have extra dimensions. LOOK RELAX THIS List testDomain = new ArrayList<>(); for (CoordinateAxis axis : testAxis) { for (Dimension dim : axis.getDimensions()) { if (!testDomain.contains(dim)) testDomain.add(dim); } } if (!CoordinateSystem.isSubset(v.getDimensionsAll(), testDomain)) { if (sbuff != null) sbuff.format(" NOT complete%n"); return false; } } return true; } /** * Determine if the CoordinateSystem cs can be made into a GridCoordSys for the Variable v. * * @param sbuff put debug information into this StringBuffer; may be null. * @param cs CoordinateSystem to check. * @param v Variable to check. * @return the GridCoordSys made from cs, else null. */ public static GridCoordSys makeGridCoordSys(Formatter sbuff, CoordinateSystem cs, VariableEnhanced v) { if (sbuff != null) { sbuff.format(" "); v.getNameAndDimensions(sbuff, false, true); sbuff.format(" check CS %s: ", cs.getName()); } if (isGridCoordSys(sbuff, cs, v)) { GridCoordSys gcs = new GridCoordSys(cs, sbuff); if (sbuff != null) sbuff.format(" OK%n"); return gcs; } return null; } ///////////////////////////////////////////////////////////////////////////// private ProjectionImpl proj; private GridCoordinate2D g2d; private CoordinateAxis horizXaxis, horizYaxis; private CoordinateAxis1D vertZaxis, ensembleAxis; private CoordinateAxis1DTime timeTaxis, runTimeAxis; private VerticalCT vCT; private VerticalTransform vt; private Dimension timeDim; private boolean isLatLon = false; /** * Create a GridCoordSys from an existing Coordinate System. * This will choose which axes are the XHoriz, YHoriz, Vertical, Time, RunTIme, Ensemble. * If theres a Projection, it will set its map area * * @param cs create from this Coordinate System * @param sbuff place information messages here, may be null */ public GridCoordSys(CoordinateSystem cs, Formatter sbuff) { super(); this.ds = cs.getNetcdfDataset(); if (cs.isGeoXY()) { horizXaxis = xAxis = cs.getXaxis(); horizYaxis = yAxis = cs.getYaxis(); ProjectionImpl p = cs.getProjection(); if (!(p instanceof RotatedPole) && !(p instanceof RotatedLatLon)) { // make a copy of the axes if they need to change horizXaxis = convertUnits(horizXaxis); horizYaxis = convertUnits(horizYaxis); } } else if (cs.isLatLon()) { horizXaxis = lonAxis = cs.getLonAxis(); horizYaxis = latAxis = cs.getLatAxis(); isLatLon = true; if (lonAxis instanceof CoordinateAxis1D) { ((CoordinateAxis1D) lonAxis).correctLongitudeWrap(); } } else throw new IllegalArgumentException("CoordinateSystem is not geoReferencing"); coordAxes.add(horizXaxis); coordAxes.add(horizYaxis); // set canonical area ProjectionImpl projOrig = cs.getProjection(); if (projOrig != null) { proj = projOrig.constructCopy(); proj.setDefaultMapArea(getBoundingBox()); // LOOK too expensive for 2D } // LOOK: require 1D vertical - need to generalize to nD vertical. CoordinateAxis z_oneD = hAxis = cs.getHeightAxis(); if ((z_oneD == null) || !(z_oneD instanceof CoordinateAxis1D)) z_oneD = pAxis = cs.getPressureAxis(); if ((z_oneD == null) || !(z_oneD instanceof CoordinateAxis1D)) z_oneD = zAxis = cs.getZaxis(); if ((z_oneD != null) && !(z_oneD instanceof CoordinateAxis1D)) z_oneD = null; CoordinateAxis z_best = hAxis; if (pAxis != null) { if ((z_best == null) || !(z_best.getRank() > pAxis.getRank())) z_best = pAxis; } if (zAxis != null) { if ((z_best == null) || !(z_best.getRank() > zAxis.getRank())) z_best = zAxis; } if ((z_oneD == null) && (z_best != null)) { // cant find one-d z but have nD z if (sbuff != null) sbuff.format("GridCoordSys needs a 1D Coordinate, instead has %s%n", z_best.getNameAndDimensions()); } if (z_oneD != null) { vertZaxis = (CoordinateAxis1D) z_oneD; coordAxes.add(vertZaxis); } else { hAxis = pAxis = zAxis = null; } // timeTaxis must be CoordinateAxis1DTime CoordinateAxis t = cs.getTaxis(); if (t != null) { if (t instanceof CoordinateAxis1D) { try { if (t instanceof CoordinateAxis1DTime) timeTaxis = (CoordinateAxis1DTime) t; else { timeTaxis = CoordinateAxis1DTime.factory(ds, t, sbuff); } tAxis = timeTaxis; coordAxes.add(timeTaxis); timeDim = t.getDimension(0); } catch (Exception e) { if (sbuff != null) sbuff.format("%s: Error reading time coord= %s err= %s%n", t.getDatasetLocation(), t.getFullName(), e.getMessage()); log.error(t.getDatasetLocation()+": Error reading time coord= "+t.getFullName(), e); throw new IllegalStateException("CoordinateSystem does not have a usable time axis"); } } else { // 2d tAxis = t; timeTaxis = null; coordAxes.add(t); // LOOK ?? } } // look for special axes ensembleAxis = (CoordinateAxis1D) cs.findAxis(AxisType.Ensemble); if (null != ensembleAxis) coordAxes.add(ensembleAxis); CoordinateAxis rtAxis = cs.findAxis(AxisType.RunTime); if (null != rtAxis) { try { if (rtAxis instanceof CoordinateAxis1DTime) runTimeAxis = (CoordinateAxis1DTime) rtAxis; else runTimeAxis = CoordinateAxis1DTime.factory(ds, rtAxis, sbuff); coordAxes.add(runTimeAxis); } catch (IOException e) { if (sbuff != null) { sbuff.format("Error reading runtime coord= %s err= %s%n", rtAxis.getFullName(), e.getMessage()); } } } // look for VerticalCT List list = cs.getCoordinateTransforms(); for (CoordinateTransform ct : list) { if (ct instanceof VerticalCT) { vCT = (VerticalCT) ct; break; } } // make name based on coordinate Collections.sort(coordAxes, new CoordinateAxis.AxisComparator()); // canonical ordering of axes this.name = makeName(coordAxes); // copy all coordinate transforms into here this.coordTrans = new ArrayList<>(cs.getCoordinateTransforms()); // collect dimensions for (CoordinateAxis axis : coordAxes) { List dims = axis.getDimensionsAll(); for (Dimension dim : dims) { if (!domain.contains(dim)) domain.add(dim); } } // WRF NMM Attribute att = getXHorizAxis().findAttribute(_Coordinate.Stagger); if (att != null) setHorizStaggerType(att.getStringValue()); } /** * Create a GridCoordSys as a section of an existing GridCoordSys. * This will create sections of the corresponding CoordinateAxes. * * @param from copy this GridCoordSys * @param t_range subset the time dimension, or null if you want all of it * @param z_range subset the vertical dimension, or null if you want all of it * @param y_range subset the y dimension, or null if you want all of it * @param x_range subset the x dimension, or null if you want all of it * @throws InvalidRangeException if any of the ranges are illegal */ public GridCoordSys(GridCoordSys from, Range t_range, Range z_range, Range y_range, Range x_range) throws InvalidRangeException { this(from, null, null, t_range, z_range, y_range, x_range); } /** * Create a GridCoordSys as a section of an existing GridCoordSys. * This will create sections of the corresponding CoordinateAxes. * * @param from copy this GridCoordSys * @param rt_range subset the runtime dimension, or null if you want all of it * @param e_range subset the ensemble dimension, or null if you want all of it * @param t_range subset the time dimension, or null if you want all of it * @param z_range subset the vertical dimension, or null if you want all of it * @param y_range subset the y dimension, or null if you want all of it * @param x_range subset the x dimension, or null if you want all of it * @throws InvalidRangeException if any of the ranges are illegal */ public GridCoordSys(GridCoordSys from, Range rt_range, Range e_range, Range t_range, Range z_range, Range y_range, Range x_range) throws InvalidRangeException { super(); CoordinateAxis xaxis = from.getXHorizAxis(); CoordinateAxis yaxis = from.getYHorizAxis(); if ((xaxis instanceof CoordinateAxis1D) && (yaxis instanceof CoordinateAxis1D)) { CoordinateAxis1D xaxis1 = (CoordinateAxis1D) xaxis; CoordinateAxis1D yaxis1 = (CoordinateAxis1D) yaxis; horizXaxis = (x_range == null) ? xaxis1 : xaxis1.section(x_range); horizYaxis = (y_range == null) ? yaxis : yaxis1.section(y_range); } else if ((xaxis instanceof CoordinateAxis2D) && (yaxis instanceof CoordinateAxis2D) && from.isLatLon()) { CoordinateAxis2D lon_axis = (CoordinateAxis2D) xaxis; CoordinateAxis2D lat_axis = (CoordinateAxis2D) yaxis; horizXaxis = lon_axis.section(y_range, x_range); horizYaxis = lat_axis.section(y_range, x_range); } else throw new IllegalArgumentException("must be 1D or 2D/LatLon "); if (from.isGeoXY()) { xAxis = horizXaxis; yAxis = horizYaxis; } else { lonAxis = horizXaxis; latAxis = horizYaxis; isLatLon = true; } coordAxes.add(horizXaxis); coordAxes.add(horizYaxis); // set canonical area ProjectionImpl projOrig = from.getProjection(); if (projOrig != null) { proj = projOrig.constructCopy(); proj.setDefaultMapArea(getBoundingBox()); // LOOK expensive for 2D } CoordinateAxis1D zaxis = from.getVerticalAxis(); if (zaxis != null) { vertZaxis = (z_range == null) ? zaxis : zaxis.section(z_range); coordAxes.add(vertZaxis); // LOOK assign hAxis, pAxis or zAxis ?? } if (from.getVerticalCT() != null) { VerticalTransform vtFrom = from.getVerticalTransform(); // LOOK may need to make sure this exists? if (vtFrom != null) vt = vtFrom.subset(t_range, z_range, y_range, x_range); vCT = from.getVerticalCT(); } CoordinateAxis1D eaxis = from.getEnsembleAxis(); if (eaxis != null) { ensembleAxis = (e_range == null) ? eaxis : eaxis.section(e_range); coordAxes.add(ensembleAxis); } CoordinateAxis taxis = from.getTimeAxis(); CoordinateAxis1DTime taxis1D = null; if (taxis != null) { if (taxis instanceof CoordinateAxis1DTime) { taxis1D = (CoordinateAxis1DTime) taxis; tAxis = timeTaxis = (t_range == null) ? taxis1D : taxis1D.section(t_range); coordAxes.add(timeTaxis); timeDim = timeTaxis.getDimension(0); } else { if ((rt_range == null) && (t_range == null)) tAxis = taxis; else { Section timeSection = new Section().appendRange(rt_range).appendRange(t_range); tAxis = (CoordinateAxis) taxis.section(timeSection); } coordAxes.add(tAxis); } } CoordinateAxis1DTime rtaxis = from.getRunTimeAxis(); if (rtaxis != null) { if (taxis1D != null) { Dimension tDim = taxis1D.getDimension(0); Dimension rtDim = rtaxis.getDimension(0); if (rtDim != null && tDim.getShortName().equals(rtDim.getShortName())) { // must use time subset range if dims match - FMRC 1D has this a lot runTimeAxis = (t_range == null) ? rtaxis : rtaxis.section(t_range); } } if (runTimeAxis == null) { // regular case of a run time axis runTimeAxis = (rt_range == null) ? rtaxis : rtaxis.section(rt_range); } coordAxes.add(runTimeAxis); } // make name based on coordinate Collections.sort(coordAxes, new CoordinateAxis.AxisComparator()); // canonical ordering of axes this.name = makeName(coordAxes); this.coordTrans = new ArrayList<>(from.getCoordinateTransforms()); // collect dimensions for (CoordinateAxis axis : coordAxes) { List dims = axis.getDimensionsAll(); for (Dimension dim : dims) { dim.setShared(true); // make them shared (section will make them unshared) if (!domain.contains(dim)) domain.add(dim); } } setHorizStaggerType(from.getHorizStaggerType()); } private CoordinateAxis convertUnits(CoordinateAxis axis) { String units = axis.getUnitsString(); SimpleUnit axisUnit = SimpleUnit.factory(units); if (axisUnit == null) { if (warnUnits) log.warn("cant parse unit= {}", units); return axis; } double factor; try { factor = axisUnit.convertTo(1.0, SimpleUnit.kmUnit); } catch (IllegalArgumentException e) { if (warnUnits) log.warn("convertUnits failed", e); return axis; } if (factor == 1.0) return axis; Array data; try { data = axis.read(); } catch (IOException e) { log.warn("convertUnits read failed", e); return axis; } DataType dtype = axis.getDataType(); if (dtype.isFloatingPoint()) { IndexIterator ii = data.getIndexIterator(); while (ii.hasNext()) ii.setDoubleCurrent(factor * ii.getDoubleNext()); CoordinateAxis newAxis = axis.copyNoCache(); newAxis.setCachedData(data, false); newAxis.setUnitsString("km"); return newAxis; } else { // convert to DOUBLE Array newData = Array.factory(DataType.DOUBLE, axis.getShape()); IndexIterator newi = newData.getIndexIterator(); IndexIterator ii = data.getIndexIterator(); while (ii.hasNext() && newi.hasNext()) newi.setDoubleNext(factor * ii.getDoubleNext()); CoordinateAxis newAxis = axis.copyNoCache(); newAxis.setDataType(DataType.DOUBLE); newAxis.setCachedData(newData, false); newAxis.setUnitsString("km"); return newAxis; } } /** * Get the vertical transform function, or null if none * * @return the vertical transform function, or null if none */ @Override public VerticalTransform getVerticalTransform() { return vt; } /** * Get the Coordinate Transform description. * * @return Coordinate Transform description, or null if none */ @Override public VerticalCT getVerticalCT() { return vCT; } // we have to delay making these, since we dont identify the dimensions specifically until now void makeVerticalTransform(GridDataset gds, Formatter parseInfo) { if (vt != null) return; // already done if (vCT == null) return; // no vt vt = vCT.makeVerticalTransform(gds.getNetcdfDataset(), timeDim); if (vt == null) { if (parseInfo != null) parseInfo.format(" - ERR can't make VerticalTransform = %s%n", vCT.getVerticalTransformType()); } else { if (parseInfo != null) parseInfo.format(" - VerticalTransform = %s%n", vCT.getVerticalTransformType()); } } /** * get the X Horizontal axis (either GeoX or Lon) */ @Override public CoordinateAxis getXHorizAxis() { return horizXaxis; } /** * get the Y Horizontal axis (either GeoY or Lat) */ @Override public CoordinateAxis getYHorizAxis() { return horizYaxis; } /** * get the Vertical axis (either Geoz, Height, or Pressure) */ @Override public CoordinateAxis1D getVerticalAxis() { return vertZaxis; } /** * get the Time axis */ @Override public CoordinateAxis getTimeAxis() { return tAxis; } /** * get the Time axis, if its 1-dimensional */ @Override public CoordinateAxis1DTime getTimeAxis1D() { return timeTaxis; } /** * get the RunTime axis, else null */ @Override public CoordinateAxis1DTime getRunTimeAxis() { return runTimeAxis; } /** * get the Ensemble axis, else null */ @Override public CoordinateAxis1D getEnsembleAxis() { return ensembleAxis; } /** * get the projection */ @Override public ProjectionImpl getProjection() { return proj; } @Override public void setProjectionBoundingBox() { // set canonical area if (proj != null) { proj.setDefaultMapArea(getBoundingBox()); // LOOK too expensive for 2D } } /** * is this a Lat/Lon coordinate system? */ @Override public boolean isLatLon() { return isLatLon; } /** * Is this a global coverage over longitude ? * @return true if isLatLon and longitude wraps */ @Override public boolean isGlobalLon() { if (!isLatLon) return false; if (!(horizXaxis instanceof CoordinateAxis1D)) return false; CoordinateAxis1D lon = (CoordinateAxis1D) horizXaxis; double first = lon.getCoordEdge(0); double last = lon.getCoordEdge((int) lon.getSize()); double min = Math.min(first, last); double max = Math.max(first, last); return (max - min) >= 360; } /** * true if increasing z coordinate values means "up" in altitude */ @Override public boolean isZPositive() { if (vertZaxis == null) return false; if (vertZaxis.getPositive() != null) { return vertZaxis.getPositive().equalsIgnoreCase(ucar.nc2.constants.CF.POSITIVE_UP); } if (vertZaxis.getAxisType() == AxisType.Height) return true; return vertZaxis.getAxisType() != AxisType.Pressure; } /** * true if x and y axes are CoordinateAxis1D and are regular */ @Override public boolean isRegularSpatial() { if (!isRegularSpatial(getXHorizAxis())) return false; if (!isRegularSpatial(getYHorizAxis())) return false; //if (!isRegularSpatial(getVerticalAxis())) return false; LOOK removed July 30, 2006 for WCS return true; } private boolean isRegularSpatial(CoordinateAxis axis) { if (axis == null) return true; if (!(axis instanceof CoordinateAxis1D)) return false; return ((CoordinateAxis1D) axis).isRegular(); } private String horizStaggerType; @Override public String getHorizStaggerType() { return horizStaggerType; } public void setHorizStaggerType(String horizStaggerType) { this.horizStaggerType = horizStaggerType; } /** * Given a point in x,y coordinate space, find the x,y index in the coordinate system. * * @param x_coord position in x coordinate space. * @param y_coord position in y coordinate space. * @param result put result (x,y) index in here, may be null * @return int[2], 0=x,1=y indices in the coordinate system of the point. These will be -1 if out of range. */ @Override public int[] findXYindexFromCoord(double x_coord, double y_coord, int[] result) { if (result == null) result = new int[2]; if ((horizXaxis instanceof CoordinateAxis1D) && (horizYaxis instanceof CoordinateAxis1D)) { result[0] = ((CoordinateAxis1D) horizXaxis).findCoordElement(x_coord); result[1] = ((CoordinateAxis1D) horizYaxis).findCoordElement(y_coord); return result; } else if ((horizXaxis instanceof CoordinateAxis2D) && (horizYaxis instanceof CoordinateAxis2D)) { if (g2d == null) g2d = new GridCoordinate2D((CoordinateAxis2D) horizYaxis, (CoordinateAxis2D) horizXaxis); int[] result2 = new int[2]; boolean found = g2d.findCoordElement(y_coord, x_coord, result2); if (found) { result[0] = result2[1]; result[1] = result2[0]; } else { result[0] = -1; result[1] = -1; } return result; } // cant happen throw new IllegalStateException("GridCoordSystem.findXYindexFromCoord"); } /** * Given a point in x,y coordinate space, find the x,y index in the coordinate system. * If outside the range, the closest point is returned, eg, 0 or n-1 depending on if the coordinate is too small or too large. * * @param x_coord position in x coordinate space. * @param y_coord position in y coordinate space. * @param result put result in here, may be null * @return int[2], 0=x,1=y indices in the coordinate system of the point. */ @Override public int[] findXYindexFromCoordBounded(double x_coord, double y_coord, int[] result) { if (result == null) result = new int[2]; if ((horizXaxis instanceof CoordinateAxis1D) && (horizYaxis instanceof CoordinateAxis1D)) { result[0] = ((CoordinateAxis1D) horizXaxis).findCoordElementBounded(x_coord); result[1] = ((CoordinateAxis1D) horizYaxis).findCoordElementBounded(y_coord); return result; } else if ((horizXaxis instanceof CoordinateAxis2D) && (horizYaxis instanceof CoordinateAxis2D)) { if (g2d == null) g2d = new GridCoordinate2D((CoordinateAxis2D) horizYaxis, (CoordinateAxis2D) horizXaxis); int[] result2 = new int[2]; g2d.findCoordElement(y_coord, x_coord, result2); // returns best guess result[0] = result2[1]; result[1] = result2[0]; return result; } // cant happen throw new IllegalStateException("GridCoordSystem.findXYindexFromCoord"); } /** * Given a lat,lon point, find the x,y index in the coordinate system. * * @param lat latitude position. * @param lon longitude position. * @param result put result in here, may be null * @return int[2], 0=x,1=y indices in the coordinate system of the point. These will be -1 if out of range. */ @Override public int[] findXYindexFromLatLon(double lat, double lon, int[] result) { Projection dataProjection = getProjection(); ProjectionPoint pp = dataProjection.latLonToProj(new LatLonPointImpl(lat, lon), new ProjectionPointImpl()); return findXYindexFromCoord(pp.getX(), pp.getY(), result); } /** * Given a lat,lon point, find the x,y index in the coordinate system. * If outside the range, the closest point is returned * * @param lat latitude position. * @param lon longitude position. * @param result put result in here, may be null * @return int[2], 0=x,1=y indices in the coordinate system of the point. */ @Override public int[] findXYindexFromLatLonBounded(double lat, double lon, int[] result) { Projection dataProjection = getProjection(); ProjectionPoint pp = dataProjection.latLonToProj(new LatLonPointImpl(lat, lon), new ProjectionPointImpl()); return findXYindexFromCoordBounded(pp.getX(), pp.getY(), result); } /** * True if there is a Time Axis. */ @Override public boolean hasTimeAxis() { return tAxis != null; } /** * True if there is a Time Axis and it is 1D. */ @Override public boolean hasTimeAxis1D() { return timeTaxis != null; } /** * @deprecated doesnt work correctly for intervals */ @Override public CoordinateAxis1DTime getTimeAxisForRun(int run_index) { if (!hasTimeAxis() || hasTimeAxis1D() || runTimeAxis == null) return null; int nruns = (int) runTimeAxis.getSize(); if ((run_index < 0) || (run_index >= nruns)) throw new IllegalArgumentException("getTimeAxisForRun index out of bounds= " + run_index); if (timeAxisForRun == null) timeAxisForRun = new CoordinateAxis1DTime[nruns]; if (timeAxisForRun[run_index] == null) timeAxisForRun[run_index] = makeTimeAxisForRun(run_index); return timeAxisForRun[run_index]; } private CoordinateAxis1DTime[] timeAxisForRun; private CoordinateAxis1DTime makeTimeAxisForRun(int run_index) { VariableDS section; try { section = (VariableDS) tAxis.slice(0, run_index); return CoordinateAxis1DTime.factory(ds, section, null); } catch (InvalidRangeException | IOException e) { e.printStackTrace(); } return null; } private ProjectionRect mapArea = null; /** * Get the x,y bounding box in projection coordinates. */ @Override public ProjectionRect getBoundingBox() { if (mapArea == null) { if ((horizXaxis == null) || !horizXaxis.isNumeric() || (horizYaxis == null) || !horizYaxis.isNumeric()) return null; // impossible // x,y may be 2D if (!(horizXaxis instanceof CoordinateAxis1D) || !(horizYaxis instanceof CoordinateAxis1D)) { /* could try to optimize this - just get cord=ners or something CoordinateAxis2D xaxis2 = (CoordinateAxis2D) horizXaxis; CoordinateAxis2D yaxis2 = (CoordinateAxis2D) horizYaxis; MAMath.MinMax */ mapArea = new ProjectionRect(horizXaxis.getMinValue(), horizYaxis.getMinValue(), horizXaxis.getMaxValue(), horizYaxis.getMaxValue()); } else { CoordinateAxis1D xaxis1 = (CoordinateAxis1D) horizXaxis; CoordinateAxis1D yaxis1 = (CoordinateAxis1D) horizYaxis; /* add one percent on each side if its a projection. WHY? double dx = 0.0, dy = 0.0; if (!isLatLon()) { dx = .01 * (xaxis1.getCoordEdge((int) xaxis1.getSize()) - xaxis1.getCoordEdge(0)); dy = .01 * (yaxis1.getCoordEdge((int) yaxis1.getSize()) - yaxis1.getCoordEdge(0)); } mapArea = new ProjectionRect(xaxis1.getCoordEdge(0) - dx, yaxis1.getCoordEdge(0) - dy, xaxis1.getCoordEdge((int) xaxis1.getSize()) + dx, yaxis1.getCoordEdge((int) yaxis1.getSize()) + dy); */ mapArea = new ProjectionRect(xaxis1.getCoordEdge(0), yaxis1.getCoordEdge(0), xaxis1.getCoordEdge((int) xaxis1.getSize()), yaxis1.getCoordEdge((int) yaxis1.getSize())); } } return mapArea; } /** * Get the Lat/Lon coordinates of the midpoint of a grid cell, using the x,y indices * * @param xindex x index * @param yindex y index * @return lat/lon coordinate of the midpoint of the cell */ @Override public LatLonPoint getLatLon(int xindex, int yindex) { double x, y; if (horizXaxis instanceof CoordinateAxis1D) { CoordinateAxis1D horiz1D = (CoordinateAxis1D) horizXaxis; x = horiz1D.getCoordValue(xindex); } else { CoordinateAxis2D horiz2D = (CoordinateAxis2D) horizXaxis; x = horiz2D.getCoordValue( yindex, xindex); } if (horizYaxis instanceof CoordinateAxis1D) { CoordinateAxis1D horiz1D = (CoordinateAxis1D) horizYaxis; y = horiz1D.getCoordValue(yindex); } else { CoordinateAxis2D horiz2D = (CoordinateAxis2D) horizYaxis; y = horiz2D.getCoordValue( yindex, xindex); } return isLatLon() ? new LatLonPointImpl(y, x) : getLatLon(x, y); } public LatLonPoint getLatLon(double xcoord, double ycoord) { Projection dataProjection = getProjection(); return dataProjection.projToLatLon(new ProjectionPointImpl(xcoord, ycoord), new LatLonPointImpl()); } private LatLonRect llbb = null; /** * Get horizontal bounding box in lat, lon coordinates. * * @return lat, lon bounding box. */ @Override public LatLonRect getLatLonBoundingBox() { if (llbb == null) { if (isLatLon()) { double startLat = horizYaxis.getMinValue(); double startLon = horizXaxis.getMinValue(); double deltaLat = horizYaxis.getMaxValue() - startLat; double deltaLon = horizXaxis.getMaxValue() - startLon; LatLonPoint llpt = new LatLonPointImpl(startLat, startLon); llbb = new LatLonRect(llpt, deltaLat, deltaLon); } else { ProjectionImpl dataProjection = getProjection(); ProjectionRect bb = getBoundingBox(); llbb = dataProjection.projToLatLonBB(bb); } } return llbb; /* // look at all 4 corners of the bounding box LatLonPointImpl llpt = (LatLonPointImpl) dataProjection.projToLatLon(bb.getLowerLeftPoint(), new LatLonPointImpl()); LatLonPointImpl lrpt = (LatLonPointImpl) dataProjection.projToLatLon(bb.getLowerRightPoint(), new LatLonPointImpl()); LatLonPointImpl urpt = (LatLonPointImpl) dataProjection.projToLatLon(bb.getUpperRightPoint(), new LatLonPointImpl()); LatLonPointImpl ulpt = (LatLonPointImpl) dataProjection.projToLatLon(bb.getUpperLeftPoint(), new LatLonPointImpl()); // Check if grid contains poles. boolean includesNorthPole = false; int[] resultNP; resultNP = findXYindexFromLatLon(90.0, 0, null); if (resultNP[0] != -1 && resultNP[1] != -1) includesNorthPole = true; boolean includesSouthPole = false; int[] resultSP; resultSP = findXYindexFromLatLon(-90.0, 0, null); if (resultSP[0] != -1 && resultSP[1] != -1) includesSouthPole = true; 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); llpt.set(latMin, lonMin); urpt.set(latMax, lonMax); llbb = new LatLonRect(llpt, urpt); } } } */ } /** * Get Index Ranges for the given lat, lon bounding box. * * @deprecated use getRangesFromLatLonRect. */ public List getLatLonBoundingBox(LatLonRect rect) throws InvalidRangeException { return getRangesFromLatLonRect(rect); } /** * Get Index Ranges for the given lat, lon bounding box. * For projection, only an approximation based on latlon corners. * Must have CoordinateAxis1D or 2D for x and y axis. * * @param rect the requested lat/lon bounding box * @return list of 2 Range objects, first y then x. */ @Override public List getRangesFromLatLonRect(LatLonRect rect) throws InvalidRangeException { double minx, maxx, miny, maxy; ProjectionImpl proj = getProjection(); if (proj != null && !(proj instanceof VerticalPerspectiveView) && !(proj instanceof MSGnavigation) && !(proj instanceof Geostationary)) { // LOOK kludge - how to do this generrally ?? // first clip the request rectangle to the bounding box of the grid LatLonRect bb = getLatLonBoundingBox(); LatLonRect rect2 = bb.intersect(rect); if (null == rect2) throw new InvalidRangeException("Request Bounding box does not intersect Grid "); rect = rect2; } CoordinateAxis xaxis = getXHorizAxis(); CoordinateAxis yaxis = getYHorizAxis(); if (isLatLon()) { LatLonPointImpl llpt = rect.getLowerLeftPoint(); LatLonPointImpl urpt = rect.getUpperRightPoint(); LatLonPointImpl lrpt = rect.getLowerRightPoint(); LatLonPointImpl ulpt = rect.getUpperLeftPoint(); 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()); // normalize to [minLon,minLon+360] double minLon = xaxis.getMinValue(); minx = LatLonPointImpl.lonNormalFrom( minx, minLon); maxx = LatLonPointImpl.lonNormalFrom( maxx, minLon); } else { ProjectionRect prect = getProjection().latLonToProjBB(rect); // allow projection to override minx = prect.getMinPoint().getX(); miny = prect.getMinPoint().getY(); maxx = prect.getMaxPoint().getX(); maxy = prect.getMaxPoint().getY(); /* see ProjectionImpl.latLonToProjBB2() Projection dataProjection = getProjection(); ProjectionPoint ll = dataProjection.latLonToProj(llpt, new ProjectionPointImpl()); ProjectionPoint ur = dataProjection.latLonToProj(urpt, new ProjectionPointImpl()); ProjectionPoint lr = dataProjection.latLonToProj(lrpt, new ProjectionPointImpl()); ProjectionPoint ul = dataProjection.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()); */ } if ((xaxis instanceof CoordinateAxis1D) && (yaxis instanceof CoordinateAxis1D)) { CoordinateAxis1D xaxis1 = (CoordinateAxis1D) xaxis; CoordinateAxis1D yaxis1 = (CoordinateAxis1D) yaxis; int minxIndex = xaxis1.findCoordElementBounded(minx); int minyIndex = yaxis1.findCoordElementBounded(miny); int maxxIndex = xaxis1.findCoordElementBounded(maxx); int maxyIndex = yaxis1.findCoordElementBounded(maxy); List list = new ArrayList<>(); list.add(new Range(Math.min(minyIndex, maxyIndex), Math.max(minyIndex, maxyIndex))); list.add(new Range(Math.min(minxIndex, maxxIndex), Math.max(minxIndex, maxxIndex))); return list; } else if ((xaxis instanceof CoordinateAxis2D) && (yaxis instanceof CoordinateAxis2D) && isLatLon()) { CoordinateAxis2D lon_axis = (CoordinateAxis2D) xaxis; CoordinateAxis2D lat_axis = (CoordinateAxis2D) yaxis; int shape[] = lon_axis.getShape(); int nj = shape[0]; int ni = shape[1]; int mini = Integer.MAX_VALUE, minj = Integer.MAX_VALUE; int maxi = -1, maxj = -1; // margolis 2/18/2010 //minx = LatLonPointImpl.lonNormal( minx ); // <-- THIS IS NEW //maxx = LatLonPointImpl.lonNormal( maxx ); // <-- THIS IS NEW // brute force, examine every point LOOK BAD for (int j = 0; j < nj; j++) { for (int i = 0; i < ni; i++) { double lat = lat_axis.getCoordValue(j, i); double lon = lon_axis.getCoordValue(j, i); //lon = LatLonPointImpl.lonNormal( lon ); // <-- THIS IS NEW if ((lat >= miny) && (lat <= maxy) && (lon >= minx) && (lon <= maxx)) { if (i > maxi) maxi = i; if (i < mini) mini = i; if (j > maxj) maxj = j; if (j < minj) minj = j; //System.out.println(j+" "+i+" lat="+lat+" lon="+lon); } } } // this is the case where no points are included if ((mini > maxi) || (minj > maxj)) { mini = 0; minj = 0; maxi = -1; maxj = -1; } ArrayList list = new ArrayList<>(); list.add(new Range(minj, maxj)); list.add(new Range(mini, maxi)); return list; } else { throw new IllegalArgumentException("must be 1D or 2D/LatLon "); } } /* private int getCrossing(CoordinateAxis2D axis) { for (int i=0; i min) return i; } */ /* private GeneralPath bbShape = null; public Shape getLatLonBoundingShape() { if (isLatLon()) return getBoundingBox(); if (bbShape == null) { ProjectionRect bb = getBoundingBox(); Projection displayProjection = displayMap.getProjection(); Projection dataProjection = getProjection(); bbShape = new GeneralPath(); LatLonPoint llpt = dataProjection.projToLatLon( bb.getX(), bb.getY()); ProjectionPoint pt = displayProjection.latLonToProj( llpt); bbShape.lineTo(pt.getX(), pt.getY()); llpt = dataProjection.projToLatLon( bb.getX(), bb.getY()+bb.getHeight()); pt = displayProjection.latLonToProj( llpt); bbShape.lineTo(pt.getX(), pt.getY()); llpt = dataProjection.projToLatLon( bb.getX()+bb.getWidth(), bb.getY()+bb.getHeight()); pt = displayProjection.latLonToProj( llpt); bbShape.lineTo(pt.getX(), pt.getY()); llpt = dataProjection.projToLatLon( bb.getX()+bb.getWidth(), bb.getY()); pt = displayProjection.latLonToProj( llpt); bbShape.lineTo(pt.getX(), pt.getY()); bbShape.closePath(); } return bbShape; } */ /** * String representation. */ @Override public String toString() { Formatter buff = new Formatter(); show(buff, false); return buff.toString(); } @Override public void show(Formatter f, boolean showCoords) { f.format("Coordinate System (%s)%n", getName()); if (getRunTimeAxis() != null) { f.format(" rt=%s (%s)", runTimeAxis.getNameAndDimensions(), runTimeAxis.getClass().getName()); if (showCoords) showCoords(runTimeAxis, f); f.format("%n"); } if (getEnsembleAxis() != null) { f.format(" ens=%s (%s)", ensembleAxis.getNameAndDimensions(), ensembleAxis.getClass().getName()); if (showCoords) showCoords(ensembleAxis, f); f.format("%n"); } if (getTimeAxis() != null) { f.format(" t=%s (%s)", tAxis.getNameAndDimensions(), tAxis.getClass().getName()); if (showCoords) showCoords(tAxis, f); f.format("%n"); } if (getVerticalAxis() != null) { f.format(" z=%s (%s)", vertZaxis.getNameAndDimensions(), vertZaxis.getClass().getName()); if (showCoords) showCoords(vertZaxis, f); f.format("%n"); } if (getYHorizAxis() != null) { f.format(" y=%s (%s)", horizYaxis.getNameAndDimensions(), horizYaxis.getClass().getName()); if (showCoords) showCoords(horizYaxis, f); f.format("%n"); } if (getXHorizAxis() != null) { f.format(" x=%s (%s)", horizXaxis.getNameAndDimensions(), horizXaxis.getClass().getName()); if (showCoords) showCoords(horizXaxis, f); f.format("%n"); } if (proj != null) f.format(" Projection: %s %s%n", proj.getName(), proj.paramsToString()); } private void showCoords(CoordinateAxis axis, Formatter f) { try { if (axis instanceof CoordinateAxis1D && axis.isNumeric()) { CoordinateAxis1D axis1D = (CoordinateAxis1D) axis; if (!axis1D.isInterval()) { double[] e = axis1D.getCoordEdges(); for (double anE : e) { f.format("%f,", anE); } } else { double[] b1 = axis1D.getBound1(); double[] b2 = axis1D.getBound2(); for (int i=0; i getCalendarDates() { if (timeTaxis != null) return timeTaxis.getCalendarDates(); else if (getRunTimeAxis() != null) return makeCalendarDates2D(); else return new ArrayList<>(); } @Override public CalendarDateRange getCalendarDateRange() { if (timeTaxis != null) return timeTaxis.getCalendarDateRange(); else if (getRunTimeAxis() != null) { List cd = makeCalendarDates2D(); int last = cd.size(); return (last > 0) ? CalendarDateRange.of(cd.get(0), cd.get(last-1)) : null; } else return null; } private List makeCalendarDates2D() { Set dates = new HashSet<>(); CoordinateAxis1DTime rtaxis = getRunTimeAxis(); List runtimes = rtaxis.getCalendarDates(); for (int i = 0; i < runtimes.size(); i++) { CoordinateAxis1DTime taxis = getTimeAxisForRun(i); if (taxis == null) throw new IllegalStateException(); List times = taxis.getCalendarDates(); for (CalendarDate time : times) dates.add(time); } // sorted list int n = dates.size(); CalendarDate[] dd = dates.toArray(new CalendarDate[n]); List dateList = Arrays.asList(dd); Collections.sort(dateList); return dateList; } ////////////////////////////////////////////////////////////////////////////////////// // cruft /** * Get the list of level names, to be used for user selection. * The ith one refers to the ith level coordinate. * * @return List of ucar.nc2.util.NamedObject, or empty list. */ public List getLevels() { if (vertZaxis == null) return new ArrayList<>(0); int n = (int) vertZaxis.getSize(); List levels = new ArrayList<>(n); for (int i = 0; i < n; i++) levels.add(new ucar.nc2.util.NamedAnything(vertZaxis.getCoordName(i), vertZaxis.getUnitsString())); return levels; } /** * Get the String name for the ith level(z) coordinate. * * @param index which level coordinate * @return level name */ public String getLevelName(int index) { if ((vertZaxis == null) || (index < 0) || (index >= vertZaxis.getSize())) throw new IllegalArgumentException("getLevelName = " + index); return vertZaxis.getCoordName(index).trim(); } /** * Get the index corresponding to the level name. * * @param name level name * @return level index, or -1 if not found */ public int getLevelIndex(String name) { if ((vertZaxis == null) || (name == null)) return -1; for (int i = 0; i < vertZaxis.getSize(); i++) { if (vertZaxis.getCoordName(i).trim().equals(name)) return i; } return -1; } /** * Get the list of time names, to be used for user selection. * The ith one refers to the ith time coordinate. * * @return List of ucar.nc2.util.NamedObject, or empty list. */ public List getTimes() { List cdates = getCalendarDates(); List times = new ArrayList<>( cdates.size()); for (CalendarDate cd: cdates) { times.add(new ucar.nc2.util.NamedAnything(cd.toString(), "calendar date")); } return times; } /////////////////////////////////////////////////////////////////////////// // deprecated /** * Given a point in x,y coordinate space, find the x,y index in the coordinate system. * * @deprecated use findXYindexFromCoord */ public int[] findXYCoordElement(double x_coord, double y_coord, int[] result) { return findXYindexFromCoord(x_coord, y_coord, result); } /** * Get the date range * @return date range * @deprecated use getCalendarDateRange */ public DateRange getDateRange() { Date[] dates = getTimeDates(); if (dates.length > 0) return new DateRange(dates[0], dates[dates.length - 1]); return null; } /** * Get the list of times as Dates. * If 2D, return list of unique dates. * * @return array of java.util.Date, or Date[0]. * @deprecated use getCalendarDates */ public java.util.Date[] getTimeDates() { if ((timeTaxis != null) && (timeTaxis.getSize() > 0)) { return timeTaxis.getTimeDates(); } else if ((tAxis != null) && (tAxis.getSize() > 0)) { return makeTimes2D(); } return new Date[0]; } private Date[] makeTimes2D() { Set dates = new HashSet<>(); try { // common case: see if it has a valid udunits unit String units = tAxis.getUnitsString(); if (units != null && SimpleUnit.isDateUnit(units) && tAxis.getDataType().isNumeric()) { DateUnit du = new DateUnit(units); Array data = tAxis.read(); data.resetLocalIterator(); while (data.hasNext()) { Date d = du.makeDate(data.nextDouble()); dates.add(d); } } else if (tAxis.getDataType() == DataType.STRING) { // otherwise, see if its a String or CHAR, and if we can parse the values as an ISO date DateFormatter formatter = new DateFormatter(); Array data = tAxis.read(); data.resetLocalIterator(); while (data.hasNext()) { Date d = formatter.getISODate((String) data.next()); dates.add(d); } } else if (tAxis.getDataType() == DataType.CHAR) { DateFormatter formatter = new DateFormatter(); ArrayChar data = (ArrayChar) tAxis.read(); ArrayChar.StringIterator iter = data.getStringIterator(); while (iter.hasNext()) { Date d = formatter.getISODate(iter.next()); dates.add(d); } } else { return new Date[0]; } } catch (Exception e) { throw new RuntimeException(e); } // sorted list int n = dates.size(); Date[] dd = dates.toArray(new Date[n]); List dateList = Arrays.asList(dd); Collections.sort(dateList); Date[] timeDates = new Date[n]; int count=0; for (Date d : dateList) timeDates[count++] = d; return timeDates; } /* old way private boolean makeTimes1D() { int n = (int) timeTaxis.getSize(); timeDates = new Date[n]; // common case: see if it has a valid udunits unit try { DateUnit du = null; String units = timeTaxis.getUnitsString(); if (units != null) du = new DateUnit(units); for (int i = 0; i < n; i++) { Date d = du.makeDate(timeTaxis.getCoordValue(i)); timeDates[i] = d; } isDate = true; return true; } catch (Exception e) { // ok to fall through } // otherwise, see if its a String, and if we can parse the values as an ISO date if ((timeTaxis.getDataType() == DataType.STRING) || (timeTaxis.getDataType() == DataType.CHAR)) { DateFormatter formatter = new DateFormatter(); for (int i = 0; i < n; i++) { String coordValue = timeTaxis.getCoordName(i); Date d = formatter.getISODate(coordValue); if (d == null) { isDate = false; return false; } else { timeDates[i] = d; } } isDate = true; return true; } return false; } */ /** * Get the string name for the ith time coordinate. * * @param index which time coordinate * @return time name. * @deprecated */ public String getTimeName(int index) { List cdates = getCalendarDates(); if ((index < 0) || (index >= cdates.size())) throw new IllegalArgumentException("getTimeName illegal index = " + index); return cdates.get(index).toString(); } /** * Get the index corresponding to the time name. * * @param name time name * @return time index, or -1 if not found * @deprecated */ public int getTimeIndex(String name) { List cdates = getCalendarDates(); for (int i=0; i < cdates.size(); i++) { if( cdates.get(i).toString().equals(name)) return i; } return -1; } /** * Only works if coordsys has 1d time axis * @deprecated use CoordinateAxis1DTime.findTimeIndexFromDate */ public int findTimeIndexFromDate(java.util.Date d) { if (timeTaxis == null) return -1; return timeTaxis.findTimeIndexFromDate(d); } /////////////////////////////////////////////////////////////////////// // experimental static 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); } static public LatLonRect getLatLonBoundingBox(Projection proj, double startx, double starty, double endx, double endy) { if (proj instanceof LatLonProjection) { double deltaLat = endy - starty; double deltaLon = endx - startx; LatLonPoint llpt = new LatLonPointImpl(starty, startx); return new LatLonRect(llpt, deltaLat, deltaLon); } ProjectionRect bb = new ProjectionRect(startx, starty, endx, endy); // look at all 4 corners of the bounding box LatLonPointImpl llpt = (LatLonPointImpl) proj.projToLatLon(bb.getLowerLeftPoint(), new LatLonPointImpl()); LatLonPointImpl lrpt = (LatLonPointImpl) proj.projToLatLon(bb.getLowerRightPoint(), new LatLonPointImpl()); LatLonPointImpl urpt = (LatLonPointImpl) proj.projToLatLon(bb.getUpperRightPoint(), new LatLonPointImpl()); LatLonPointImpl ulpt = (LatLonPointImpl) proj.projToLatLon(bb.getUpperLeftPoint(), new LatLonPointImpl()); // Check if grid contains poles. LOOK disabled boolean includesNorthPole = false; /* int[] resultNP = new int[2]; resultNP = findXYindexFromLatLon(90.0, 0, null); if (resultNP[0] != -1 && resultNP[1] != -1) includesNorthPole = true; */ boolean includesSouthPole = false; /* int[] resultSP = new int[2]; resultSP = findXYindexFromLatLon(-90.0, 0, null); 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); } 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); llpt.set(latMin, lonMin); urpt.set(latMax, lonMax); llbb = new LatLonRect(llpt, urpt); } return llbb; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy