/** * _more_ * * @param stationLat _more_ * @param stationLon _more_ * @throws RemoteException _more_ * @throws VisADException _more_ */ protected void initLinePosition(float stationLat, float stationLon) throws VisADException, RemoteException { if (getVerticalAxisRange() == null) { setVerticalAxisRange(new Range(0, 20000)); } // get station location from the data coordinate transform LatLonPointImpl lp1 = Bearing.findPoint(stationLat, stationLon, 0, 150.0f, null); LatLonPointImpl lp2 = Bearing.findPoint(stationLat, stationLon, 180, 150.0f, null); startLocation = new EarthLocationTuple(lp2.getLatitude(), lp2.getLongitude(), 0.0); endLocation = new EarthLocationTuple(lp1.getLatitude(), lp1.getLongitude(), 0.0); }
/** * @param refPt The geodetic position of the reference point. * @param neiPt The holder for the geodetic position of the neighboring grid point. * @param lat The latitude of the neighboring grid point. * @param lon The longitude of the neighboring grid point. * @param azTerm An amount in degrees to be added to the computed azimuth. * @param bearing The holder for the computed range and bearing from the reference point to the * neighboring grid point. * @param hat 2-element output array for computed (x,y) components of unit vector. */ private static void compute( LatLonPointImpl refPt, LatLonPointImpl neiPt, float lat, float lon, float azTerm, Bearing bearing, float[] hat) { neiPt.set(lat, lon); Bearing.calculateBearing(refPt, neiPt, bearing); float az = (float) Math.toRadians(bearing.getAngle() + azTerm); // System.out.println("bearing.Angle = " + bearing.getAngle() + "; azTerm = " + azTerm+ "; // result= " + Math.toDegrees(az)); hat[0] = (float) Math.sin(az); hat[1] = (float) Math.cos(az); }
/** * @param refPt The geodetic position of the reference point. * @param neiPt The holder for the geodetic position of the neighboring grid point. * @param lat The latitude of the neighboring grid point. * @param lon The longitude of the neighboring grid point. * @param azTerm An amount in degrees to be added to the computed azimuth. * @param wind Magnitude of grid-relative wind component. * @param bearing The holder for the computed range and bearing from the reference point to the * neighboring grid point. * @param uv 2-element output array for computed (U,V) wind components. */ private static void compute( LatLonPointImpl refPt, LatLonPointImpl neiPt, float lat, float lon, float azTerm, float wind, Bearing bearing, float[] uv) { neiPt.set(lat, lon); Bearing.calculateBearing(refPt, neiPt, bearing); float az = (float) Math.toRadians(bearing.getAngle() + azTerm); float xhat = (float) Math.sin(az); float yhat = (float) Math.cos(az); uv[0] = xhat * wind; uv[1] = yhat * wind; }
/** * Test the calculations - forward and back * * @param args non used */ public static void main(String[] args) { // Bearing workBearing = new Bearing(); LatLonPointImpl pt1 = new LatLonPointImpl(40, -105); LatLonPointImpl pt2 = new LatLonPointImpl(37.4, -118.4); Bearing b = calculateBearing(pt1, pt2, null); System.out.println("Bearing from " + pt1 + " to " + pt2 + " = \n\t" + b); LatLonPointImpl pt3 = new LatLonPointImpl(); pt3 = findPoint(pt1, b.getAngle(), b.getDistance(), pt3); System.out.println("using first point, angle and distance, found second point at " + pt3); pt3 = findPoint(pt2, b.getBackAzimuth(), b.getDistance(), pt3); System.out.println("using second point, backazimuth and distance, found first point at " + pt3); /* uncomment for timing tests for(int j=0;j<10;j++) { long t1 = System.currentTimeMillis(); for(int i=0;i<30000;i++) { workBearing = Bearing.calculateBearing(42.5,-93.0, 48.9,-117.09,workBearing); } long t2 = System.currentTimeMillis(); System.err.println ("time:" + (t2-t1)); } */ }
/** * @param grid The grid. * @param gridWinds The grid-relative winds. * @param cs The coordinate system transformation of the grid. * @param index The index of the grid-relative wind component. * @param latI The index of latitude in the reference coordinate system. * @param lonI The index of longitude in the reference coordinate system. * @param us The array in which to add the computed U-component of the wind. * @param us The array in which to add the computed V-component of the wind. * @param vs * @throws IndexOutOfBoundsException if <code>gridWinds</code>, <code>us * </code>, or <code>vs</code> is too small. * @throws VisADException if a VisAD failure occurs. */ private static void addComponent( SampledSet grid, float[][] gridWinds, CoordinateSystem cs, int index, int latI, int lonI, float[] us, float[] vs) throws VisADException { int[][] neighbors = grid.getNeighbors(index); LatLonPointImpl refPt = new LatLonPointImpl(); LatLonPointImpl neiPt = new LatLonPointImpl(); Bearing bearing = new Bearing(); float[] uv1 = new float[2]; float[] uv2 = new float[2]; boolean hasCS = cs != null; float[][] domainSamples = grid.getSamples(false); float[][] crefCoords = (hasCS) ? cs.toReference(Set.copyFloats(domainSamples)) : domainSamples; // If the grid is lat/lon or has an IdentityCoordinateSystem // don't do the rotation // TODO: handle rotated lat/lon grids if (!hasCS || (crefCoords == domainSamples) || (Arrays.equals(crefCoords[latI], domainSamples[latI]) && Arrays.equals(crefCoords[lonI], domainSamples[lonI]))) { // us = gridWinds[0]; // vs = gridWinds[1]; System.arraycopy(gridWinds[0], 0, us, 0, us.length); System.arraycopy(gridWinds[1], 0, vs, 0, vs.length); } else { for (int i = 0; i < neighbors.length; i++) { float[][] refCoords = grid.indexToValue(new int[] {i}); if (hasCS) { refCoords = cs.toReference(refCoords); } float[][] neiCoords = grid.indexToValue(neighbors[i]); if (hasCS) { neiCoords = cs.toReference(neiCoords); } refPt.set(refCoords[latI][0], refCoords[lonI][0]); compute( refPt, neiPt, neiCoords[latI][0], neiCoords[lonI][0], -180, gridWinds[index][i], bearing, uv1); float d1 = (float) bearing.getDistance(); compute( refPt, neiPt, neiCoords[latI][1], neiCoords[lonI][1], 0, gridWinds[index][i], bearing, uv2); float d2 = (float) bearing.getDistance(); boolean bad1 = Double.isNaN(d1); boolean bad2 = Double.isNaN(d2); if (bad1 && bad2) { us[i] = Float.NaN; vs[i] = Float.NaN; } else { if (bad1) { us[i] += uv2[0]; vs[i] += uv2[1]; } else if (bad2) { us[i] += uv1[0]; vs[i] += uv1[1]; } else { float tot = d1 + d2; float c1 = d2 / tot; float c2 = d1 / tot; us[i] += c1 * uv1[0] + c2 * uv2[0]; vs[i] += c1 * uv1[1] + c2 * uv2[1]; } } } } }
/** * I have no idea what this does. * * @param grid sampling grid * @param index some sort of index * @return a new flat field with something different * @throws RemoteException Java RMI error * @throws VisADException VisAD error */ private static FlatField hatFieldOld(Set grid, int index) throws VisADException, RemoteException { CoordinateSystem cs = grid.getCoordinateSystem(); boolean hasCS = (cs != null); RealTupleType rtt = (hasCS) ? cs.getReference() : ((SetType) grid.getType()).getDomain(); int latI = rtt.getIndex(RealType.Latitude); if (latI == -1) { throw new IllegalArgumentException(grid.toString()); } int lonI = rtt.getIndex(RealType.Longitude); if (lonI == -1) { throw new IllegalArgumentException(grid.toString()); } if (grid.getManifoldDimension() < 2) { throw new IllegalArgumentException(grid.toString()); } int[][] neighbors = grid.getNeighbors(index); LatLonPointImpl refPt = new LatLonPointImpl(); LatLonPointImpl neiPt = new LatLonPointImpl(); Bearing bearing = new Bearing(); float[] hat1 = new float[2]; float[] hat2 = new float[2]; float[][] hat = new float[2][grid.getLength()]; for (int i = 0; i < neighbors.length; i++) { float[][] refCoords = grid.indexToValue(new int[] {i}); if (hasCS) { refCoords = cs.toReference(refCoords); } float[][] neiCoords = grid.indexToValue(neighbors[i]); if (hasCS) { neiCoords = cs.toReference(neiCoords); } refPt.set(refCoords[latI][0], refCoords[lonI][0]); compute(refPt, neiPt, neiCoords[latI][0], neiCoords[lonI][0], -180, bearing, hat1); float d1 = (float) bearing.getDistance(); compute(refPt, neiPt, neiCoords[latI][1], neiCoords[lonI][1], 0, bearing, hat2); float d2 = (float) bearing.getDistance(); boolean bad1 = Double.isNaN(d1); boolean bad2 = Double.isNaN(d2); if (bad1 && bad2) { hat[0][i] = Float.NaN; hat[1][i] = Float.NaN; } else { if (bad1) { hat[0][i] = hat2[0]; hat[1][i] = hat2[1]; } else if (bad2) { hat[0][i] = hat1[0]; hat[1][i] = hat1[1]; } else { float tot = d1 + d2; float c1 = d2 / tot; float c2 = d1 / tot; float xhat = c1 * hat1[0] + c2 * hat2[0]; float yhat = c1 * hat1[1] + c2 * hat2[1]; float mag = (float) Math.sqrt(xhat * xhat + yhat * yhat); hat[0][i] = xhat / mag; hat[1][i] = yhat / mag; } } } FlatField hatField = new FlatField( new FunctionType( ((SetType) grid.getType()).getDomain(), new RealTupleType( RealType.getRealType("xHat", CommonUnit.dimensionless), RealType.getRealType("yHat", CommonUnit.dimensionless))), grid); hatField.setSamples(hat, false); return hatField; }
/** * The returned {@link visad.FlatField} will have NaN-s for those unit vector components that * could not be computed. * * @param grid The spatial grid. * @param index The index of the manifold dimension along which to compute the unit vector. * @return A field of components of the unit vector for the given manifold dimension. * @throws NullPointerException if the grid is <code>null</code>. * @throws IllegalArgumentException if the manifold dimension of the grid is less than 2 or if the * grid doesn't contain {@link visad.RealType#Latitude} and {@link visad.RealType#Longitude}. * @throws VisADException if a VisAD failure occurs. * @throws RemoteException if a Java RMI failure occurs. */ private static FlatField hatFieldNew(Set grid, int index) throws VisADException, RemoteException { CoordinateSystem cs = grid.getCoordinateSystem(); boolean hasCS = cs != null; RealTupleType rtt = (hasCS) ? cs.getReference() : ((SetType) grid.getType()).getDomain(); int latI = rtt.getIndex(RealType.Latitude); if (latI == -1) { throw new IllegalArgumentException(rtt.toString()); } int lonI = rtt.getIndex(RealType.Longitude); if (lonI == -1) { throw new IllegalArgumentException(rtt.toString()); } if (grid.getManifoldDimension() < 2) { throw new IllegalArgumentException(grid.toString()); } int[][] neighbors = grid.getNeighbors(index); LatLonPointImpl refPt = new LatLonPointImpl(); LatLonPointImpl neiPt = new LatLonPointImpl(); Bearing bearing = new Bearing(); float[] hat1 = new float[2]; float[] hat2 = new float[2]; float[][] hat = new float[2][grid.getLength()]; float[][] refCoords = null; float[][] neiCoords = null; float[][] domainSamples = grid.getSamples(false); refCoords = (hasCS) ? cs.toReference(Set.copyFloats(domainSamples)) : domainSamples; // If the grid is lat/lon or has an IdentityCoordinateSystem // don't do the rotation // TODO: handle rotated lat/lon grids if (!hasCS || (refCoords == domainSamples) || (Arrays.equals(refCoords[latI], domainSamples[latI]) && Arrays.equals(refCoords[lonI], domainSamples[lonI]))) { if (index == 0) { Arrays.fill(hat[0], 1); Arrays.fill(hat[1], 0); } else { Arrays.fill(hat[0], 0); Arrays.fill(hat[1], 1); } } else { float latBefore, lonBefore, latAfter, lonAfter; // int backOffset = (index==0) ? -180 : 0; // int foreOffset = (index==0) ? 0 : -180; int backOffset = -180; int foreOffset = 0; for (int i = 0; i < neighbors.length; i++) { refPt.set(refCoords[latI][i], refCoords[lonI][i]); if ((neighbors[i][0] < 0) || (neighbors[i][0] >= neighbors.length)) { latBefore = Float.NaN; lonBefore = Float.NaN; } else { latBefore = refCoords[latI][neighbors[i][0]]; lonBefore = refCoords[lonI][neighbors[i][0]]; } if ((neighbors[i][1] < 0) || (neighbors[i][1] >= neighbors.length)) { latAfter = Float.NaN; lonAfter = Float.NaN; } else { latAfter = refCoords[latI][neighbors[i][1]]; lonAfter = refCoords[lonI][neighbors[i][1]]; } compute(refPt, neiPt, latBefore, lonBefore, backOffset, bearing, hat1); float d1 = (float) bearing.getDistance(); compute(refPt, neiPt, latAfter, lonAfter, foreOffset, bearing, hat2); float d2 = (float) bearing.getDistance(); boolean bad1 = Double.isNaN(d1); boolean bad2 = Double.isNaN(d2); if (bad1 && bad2) { hat[0][i] = Float.NaN; hat[1][i] = Float.NaN; } else { if (bad1) { hat[0][i] = hat2[0]; hat[1][i] = hat2[1]; } else if (bad2) { hat[0][i] = hat1[0]; hat[1][i] = hat1[1]; } else { float tot = d1 + d2; float c1 = d2 / tot; float c2 = d1 / tot; float xhat = c1 * hat1[0] + c2 * hat2[0]; float yhat = c1 * hat1[1] + c2 * hat2[1]; float mag = (float) Math.sqrt(xhat * xhat + yhat * yhat); hat[0][i] = xhat / mag; hat[1][i] = yhat / mag; } } } } FlatField hatField = new FlatField( new FunctionType( ((SetType) grid.getType()).getDomain(), new RealTupleType( RealType.getRealType("xHat", CommonUnit.dimensionless), RealType.getRealType("yHat", CommonUnit.dimensionless))), grid); hatField.setSamples(hat, false); return hatField; }
/** * Computes distance (in km), azimuth (degrees clockwise positive from North, 0 to 360), and back * azimuth (degrees clockwise positive from North, 0 to 360), from latitude-longituide point pt1 * to latitude-longituide pt2. * * <p>Algorithm from U.S. National Geodetic Survey, FORTRAN program "inverse," subroutine * "INVER1," by L. PFEIFER and JOHN G. GERGEN. See * http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html * * <p>Original documentation: <br> * SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY <br> * MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS <br> * EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL <br> * STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE Reference ellipsoid is the WGS-84 * ellipsoid. <br> * See http://www.colorado.edu/geography/gcraft/notes/datum/elist.html * * <p>Requires close to 1.4 E-5 seconds wall clock time per call on a 550 MHz Pentium with Linux * 7.2. * * @param e Earth object (defines radius and flattening) * @param lat1 Lat of point 1 * @param lon1 Lon of point 1 * @param lat2 Lat of point 2 * @param lon2 Lon of point 2 * @param result put result here, or null to allocate * @return a Bearing object with distance (in km), azimuth from pt1 to pt2 (degrees, 0 = north, * clockwise positive) */ public static Bearing calculateBearing( Earth e, double lat1, double lon1, double lat2, double lon2, Bearing result) { if (result == null) { result = new Bearing(); } if ((lat1 == lat2) && (lon1 == lon2)) { result.distance = 0; result.azimuth = 0; result.backazimuth = 0; return result; } A = e.getMajor(); F = e.getFlattening(); R = 1.0 - F; // Algorithm from National Geodetic Survey, FORTRAN program "inverse," // subroutine "INVER1," by L. PFEIFER and JOHN G. GERGEN. // http://www.ngs.noaa.gov/TOOLS/Inv_Fwd/Inv_Fwd.html // Conversion to JAVA from FORTRAN was made with as few changes as possible // to avoid errors made while recasting form, and to facilitate any future // comparisons between the original code and the altered version in Java. // Original documentation: // SOLUTION OF THE GEODETIC INVERSE PROBLEM AFTER T.VINCENTY // MODIFIED RAINSFORD'S METHOD WITH HELMERT'S ELLIPTICAL TERMS // EFFECTIVE IN ANY AZIMUTH AND AT ANY DISTANCE SHORT OF ANTIPODAL // STANDPOINT/FOREPOINT MUST NOT BE THE GEOGRAPHIC POLE // A IS THE SEMI-MAJOR AXIS OF THE REFERENCE ELLIPSOID // F IS THE FLATTENING (NOT RECIPROCAL) OF THE REFERNECE ELLIPSOID // LATITUDES GLAT1 AND GLAT2 // AND LONGITUDES GLON1 AND GLON2 ARE IN RADIANS POSITIVE NORTH AND EAST // FORWARD AZIMUTHS AT BOTH POINTS RETURNED IN RADIANS FROM NORTH // // Reference ellipsoid is the WGS-84 ellipsoid. // See http://www.colorado.edu/geography/gcraft/notes/datum/elist.html // FAZ is forward azimuth in radians from pt1 to pt2; // BAZ is backward azimuth from point 2 to 1; // S is distance in meters. // // Conversion to JAVA from FORTRAN was made with as few changes as possible // to avoid errors made while recasting form, and to facilitate any future // comparisons between the original code and the altered version in Java. // // IMPLICIT REAL*8 (A-H,O-Z) // COMMON/CONST/PI,RAD // COMMON/ELIPSOID/A,F double GLAT1 = rad * lat1; double GLAT2 = rad * lat2; double TU1 = R * Math.sin(GLAT1) / Math.cos(GLAT1); double TU2 = R * Math.sin(GLAT2) / Math.cos(GLAT2); double CU1 = 1. / Math.sqrt(TU1 * TU1 + 1.); double SU1 = CU1 * TU1; double CU2 = 1. / Math.sqrt(TU2 * TU2 + 1.); double S = CU1 * CU2; double BAZ = S * TU2; double FAZ = BAZ * TU1; double GLON1 = rad * lon1; double GLON2 = rad * lon2; double X = GLON2 - GLON1; double D, SX, CX, SY, CY, Y, SA, C2A, CZ, E, C; int loopCnt = 0; do { loopCnt++; // Check for an infinite loop if (loopCnt > 1000) { throw new IllegalArgumentException( "Too many iterations calculating bearing:" + lat1 + " " + lon1 + " " + lat2 + " " + lon2); } SX = Math.sin(X); CX = Math.cos(X); TU1 = CU2 * SX; TU2 = BAZ - SU1 * CU2 * CX; SY = Math.sqrt(TU1 * TU1 + TU2 * TU2); CY = S * CX + FAZ; Y = Math.atan2(SY, CY); SA = S * SX / SY; C2A = -SA * SA + 1.; CZ = FAZ + FAZ; if (C2A > 0.) { CZ = -CZ / C2A + CY; } E = CZ * CZ * 2. - 1.; C = ((-3. * C2A + 4.) * F + 4.) * C2A * F / 16.; D = X; X = ((E * CY * C + CZ) * SY * C + Y) * SA; X = (1. - C) * X * F + GLON2 - GLON1; // IF(DABS(D-X).GT.EPS) GO TO 100 } while (Math.abs(D - X) > EPS); if (loopCnt > maxLoopCnt) { maxLoopCnt = loopCnt; // System.err.println("loopCnt:" + loopCnt); } FAZ = Math.atan2(TU1, TU2); BAZ = Math.atan2(CU1 * SX, BAZ * CX - SU1 * CU2) + Math.PI; X = Math.sqrt((1. / R / R - 1.) * C2A + 1.) + 1.; X = (X - 2.) / X; C = 1. - X; C = (X * X / 4. + 1.) / C; D = (0.375 * X * X - 1.) * X; X = E * CY; S = 1. - E - E; S = ((((SY * SY * 4. - 3.) * S * CZ * D / 6. - X) * D / 4. + CZ) * SY * D + Y) * C * A * R; result.distance = S / 1000.0; // meters to km result.azimuth = FAZ * deg; // radians to degrees if (result.azimuth < 0.0) { result.azimuth += 360.0; // reset azs from -180 to 180 to 0 to 360 } result.backazimuth = BAZ * deg; // radians to degrees; already in 0 to 360 range return result; }
/** * Handle glyph moved * * @throws RemoteException On badness * @throws VisADException On badness */ public void updateLocation() throws VisADException, RemoteException { super.updateLocation(); if (points.size() < 2) { return; } if (showText) { setText(startTextDisplayable, 0, startText, startTextType); setText(endTextDisplayable, 1, endText, endTextType); } checkBoxVisibility(); if ((maxDataDistance == null) || (maxDistanceBox == null)) { return; } double km = maxDataDistance.getValue(CommonUnit.meter) / 1000.0; if (km > 2000) { return; } EarthLocation p1 = (EarthLocation) points.get(0); EarthLocation p2 = (EarthLocation) points.get(1); MathType mathType = RealTupleType.LatitudeLongitudeAltitude; Bearing baseBearing = Bearing.calculateBearing( p1.getLatitude().getValue(), p1.getLongitude().getValue(), p2.getLatitude().getValue(), p2.getLongitude().getValue(), null); double baseAngle = baseBearing.getAngle(); LatLonPointImpl[] llps = new LatLonPointImpl[] { Bearing.findPoint( p1.getLatitude().getValue(), p1.getLongitude().getValue(), baseAngle + 90.0, km, null), Bearing.findPoint( p2.getLatitude().getValue(), p2.getLongitude().getValue(), baseAngle + 90.0, km, null), Bearing.findPoint( p2.getLatitude().getValue(), p2.getLongitude().getValue(), baseAngle - 90, km, null), Bearing.findPoint( p1.getLatitude().getValue(), p1.getLongitude().getValue(), baseAngle - 90, km, null), Bearing.findPoint( p1.getLatitude().getValue(), p1.getLongitude().getValue(), baseAngle + 90.0, km, null) }; float[][] lineVals = getPointValues(); float alt = lineVals[2][0]; lineVals = new float[3][llps.length]; for (int i = 0; i < lineVals[0].length; i++) { lineVals[0][i] = (float) llps[i].getLatitude(); lineVals[1][i] = (float) llps[i].getLongitude(); } float[][] tmp = new float[3][]; for (int i = 0; i < lineVals[0].length - 1; i++) { tmp[0] = Misc.merge( tmp[0], Misc.interpolate( 2 + getNumInterpolationPoints(), lineVals[0][i], lineVals[0][i + 1])); tmp[1] = Misc.merge( tmp[1], Misc.interpolate( 2 + getNumInterpolationPoints(), lineVals[1][i], lineVals[1][i + 1])); } tmp[2] = new float[tmp[0].length]; lineVals = tmp; for (int i = 0; i < lineVals[0].length; i++) { lineVals[2][i] = alt; } Data theData = new Gridded3DSet(mathType, lineVals, lineVals[0].length); maxDistanceBox.setData(theData); }