/*
* Copyright 1998-2015 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.nc2.iosp.gempak;
import ucar.nc2.iosp.grid.GridDefRecord;
/**
* Class to hold the grid navigation information.
* <pre>
* PROJ is the map projection, projection angles, and margins separated
* by slashes and an optional image drop flag separated from the rest by
* a bar:
*
* map proj / ang1;ang2;ang3 / l;b;r;t (margins) | image drop flag
*
* For all map projections, the lower left and upper right corners of
* the graphics area should be specified in GAREA.
*
* The following simple map projections may be specified:
*
* MER Mercator
* NPS North Polar Stereographic
* SPS South Polar Stereographic
* LCC Northern Hemisphere Lambert Conic Conformal
* SCC Southern Hemisphere Lambert Conic Conformal
* CED Cylindrical Equidistant
* MCD Modified Cylindrical Equidistant
* NOR North Orthographic
* SOR South Orthographic
*
*
* The following full map projections may also be specified:
*
* MER (CYL) Mercator
* CED (CYL) Cylindrical Equidistant
* MCD (CYL) Modified Cylindrical Equidistant
* STR (AZM) Polar Stereographic
* AED (AZM) Azimuthal Equidistant
* ORT (AZM) Orthographic
* LEA (AZM) Lambert equal area
* GNO (AZM) Gnomonic
* LCC (CON) Northern Hemisphere Lambert Conic Conformal
* SCC (CON) Southern Hemisphere Lambert Conic Conformal
*
*
* In addition for full map projections, three angles MUST be specified
* in PROJ. The angles have the following meanings for the different
* projection classes:
*
* CYL angle1 -- latitude of origin on the projection cylinder
* 0 = Equator
* angle2 -- longitude of origin on the projection cylinder
* 0 = Greenwich meridian
* angle3 -- angle to skew the projection by rotation of
* the cylindrical surface of projection about
* the line from the Earth's center passing
* through the origin point. This results in
* curved latitude and longitude lines.
*
* If angle3 is greater than 360 or less than -360
* degrees, then the rectangular Cartesian coordinate
* system on the projection plane is rotated
* +/- |angle3|-360 degrees. This results in
* latitude and longitude lines that are skewed
* with respect to the edge of the map. This option
* is only valid when specifying a map projection and
* is not available for grid projections.
*
* The difference between |angle3| < 360 and
* |angle3| > 360 is that, in the former case,
* the rotation is applied to the developable
* cylindrical surface before projection and
* subsequent development; while, in the latter
* case, the rotation is applied to the Cartesian
* coordinate system in the plane after development.
* Development here refers to the mathematical
* flattening of the surface of projection into a
* planar surface.
*
* Exception:
*
* MCD angle1 -- scaling factor for latitude
* 0 = default scaling (1/cos(avglat))
* angle2 -- longitude of origin (center longitude)
* angle3 -- not used
*
*
* AZM angle1 -- latitude of the projection's point of tangency
* angle2 -- longitude of the projection's point of tangency
* angle3 -- angle to skew the projection by rotation about
* the line from the Earth's center passing
* through the point of tangency
*
* CON angle1 -- standard latitude 1
* angle2 -- polon is the central longitude
* angle3 -- standard latitude 2
*
* The angles for the full map projection types are given as three numbers
* separated with semicolons. Note that THREE angles must be entered even
* if some angles are not used.
*
* Note that transverse projections may be obtained using a cylindrical
* projection with the first angle set to either 90 or -90. The second
* angle is the longitude at which the cylinder axis intersects the
* equator. This will be the transformed location of the "south" pole
* when the first angle is 90 or the "north" pole when the first angle
* is -90. For example, if angle1 = 90 and angle2 = 0, the axis of the
* cylinder of projection is perpendicular to the earth's axis and enters
* the earth at 0N 0E and emerges at 0N 180E. The great circle formed
* by 90E and 90W becomes the "equator" on the cylinder. This cylinder
* is ideal for a transverse cylindrical projection of locations on the
* continent of North America.
* </pre>
*
*
* @author IDV Development Team
*/
public class NavigationBlock extends GridDefRecord {
/** raw values */
float[] vals = null;
/** projection type */
private String proj;
/**
* Create a new grid nav block
*/
public NavigationBlock() {}
/**
* Create a new grid nav block with the values
*
* @param words analysis block values
*/
public NavigationBlock(float[] words) {
setValues(words);
}
/**
* Set the grid nav block values
*
* @param values the raw values
*/
public void setValues(float[] values) {
vals = values;
proj = GempakUtil.ST_ITOC(Float.floatToIntBits(vals[1])).trim();
addParam(PROJ, proj);
addParam(GDS_KEY, this.toString());
setParams();
}
/**
* Print out the navibation block so it looks something like this:
* <pre>
* PROJECTION: LCC
* ANGLES: 25.0 -95.0 25.0
* GRID SIZE: 93 65
* LL CORNER: 12.19 -133.46
* UR CORNER: 57.29 -49.38
* </pre>
*
* @return a String representation of this.
*/
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("\n PROJECTION: ");
buf.append(proj);
buf.append("\n ANGLES: ");
buf.append(vals[10]);
buf.append(" ");
buf.append(vals[11]);
buf.append(" ");
buf.append(vals[12]);
buf.append("\n GRID SIZE: ");
buf.append(vals[4]);
buf.append(" ");
buf.append(vals[5]);
buf.append("\n LL CORNER: ");
buf.append(vals[6]);
buf.append(" ");
buf.append(vals[7]);
buf.append("\n UR CORNER: ");
buf.append(vals[8]);
buf.append(" ");
buf.append(vals[9]);
return buf.toString();
}
/**
* Set the parameters for the GDS.
* TODO Add the following:
* The following simple map projections may be specified:
*
* NOR North Orthographic
* SOR South Orthographic
* MER (CYL) Mercator
* CED (CYL) Cylindrical Equidistant
* MCD (CYL) Modified Cylindrical Equidistant
* STR (AZM) Polar Stereographic
* AED (AZM) Azimuthal Equidistant
* ORT (AZM) Orthographic
* LEA (AZM) Lambert equal area
* GNO (AZM) Gnomonic
* </TODO>
*
* In addition for full map projections, three angles MUST be specified
* in PROJ. The angles have the following meanings for the different
* projection classes:
*
* CYL angle1 -- latitude of origin on the projection cylinder
* 0 = Equator
* angle2 -- longitude of origin on the projection cylinder
* 0 = Greenwich meridian
* angle3 -- angle to skew the projection by rotation of
* the cylindrical surface of projection about
* the line from the Earth's center passing
* through the origin point. This results in
* curved latitude and longitude lines.
*
* If angle3 is greater than 360 or less than -360
* degrees, then the rectangular Cartesian coordinate
* system on the projection plane is rotated
* +/- |angle3|-360 degrees. This results in
* latitude and longitude lines that are skewed
* with respect to the edge of the map. This option
* is only valid when specifying a map projection and
* is not available for grid projections.
*
* The difference between |angle3| < 360 and
* |angle3| > 360 is that, in the former case,
* the rotation is applied to the developable
* cylindrical surface before projection and
* subsequent development; while, in the latter
* case, the rotation is applied to the Cartesian
* coordinate system in the plane after development.
* Development here refers to the mathematical
* flattening of the surface of projection into a
* planar surface.
*
* Exception:
*
* MCD angle1 -- scaling factor for latitude
* 0 = default scaling (1/cos(avglat))
* angle2 -- longitude of origin (center longitude)
* angle3 -- not used
*
*
* AZM angle1 -- latitude of the projection's point of tangency
* angle2 -- longitude of the projection's point of tangency
* angle3 -- angle to skew the projection by rotation about
* the line from the Earth's center passing
* through the point of tangency
*
* CON angle1 -- standard latitude 1
* angle2 -- polon is the central longitude
* angle3 -- standard latitude 2
*
*/
private void setParams() {
String angle1 = String.valueOf(vals[10]);
String angle2 = String.valueOf(vals[11]);
String angle3 = String.valueOf(vals[12]);
String lllat = String.valueOf(vals[6]);
String lllon = String.valueOf(vals[7]);
String urlat = String.valueOf(vals[8]);
String urlon = String.valueOf(vals[9]);
addParam(NX, String.valueOf(vals[4]));
addParam(NY, String.valueOf(vals[5]));
addParam(LA1, lllat);
addParam(LO1, lllon);
addParam(LA2, urlat);
addParam(LO2, urlon);
switch (proj) {
case "STR":
case "NPS":
case "SPS":
addParam(LOV, angle2);
// TODO: better to just set pole?
if (proj.equals("SPS")) {
addParam("NpProj", "false");
}
break;
case "LCC":
case "SCC":
addParam(LATIN1, angle1);
addParam(LOV, angle2);
addParam(LATIN2, angle3);
// TODO: test this
break;
case "MER":
case "MCD":
String standardLat;
if (vals[10] == 0) { // use average latitude
float lat = (vals[8] + vals[6]) / 2;
standardLat = String.valueOf(lat);
} else {
standardLat = angle1;
}
addParam("Latin", standardLat);
addParam(LOV, angle2);
break;
case "CED":
double lllatv = vals[6];
double lllonv = vals[7];
double urlatv = vals[8];
double urlonv = vals[9];
if (urlonv <= lllonv) {
urlonv += 360.;
}
double dx = Math.abs((urlonv - lllonv) / (vals[4] - 1));
double dy = Math.abs((urlatv - lllatv) / (vals[5] - 1));
addParam(DX, String.valueOf(dx));
addParam(DY, String.valueOf(dy));
addParam(LO2, String.valueOf(urlonv));
break;
}
}
/**
* Get a short name for this GDSKey for the netCDF group.
* Subclasses should implement as a short description
* @return short name
*/
public String getGroupName() {
return proj + "_" + getParam(NX) + "x" + getParam(NY);
}
}