//
// GctpFunction.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.data.hdfeos;

import java.lang.Math.*;

public class GctpFunction
{

  static final int GEO = 0;
  static final int UTM = 1;
  static final int SPCS = 2;
  static final int ALBERS = 3;
  static final int LAMCC = 4;
  static final int MERCAT = 5;
  static final int PS = 6;
  static final int POLYC = 7;
  static final int EQUIDC = 8;
  static final int TM = 9;
  static final int STEREO = 10;
  static final int LAMAZ = 11;
  static final int AZMEQD = 12;
  static final int GNOMON = 13;
  static final int ORTHO = 14;
  static final int GVNSP = 15;
  static final int SNSOID = 16;
  static final int EQRECT = 17;
  static final int MILLER = 18;
  static final int VGRINT = 19;
  static final int HOM = 20;
  static final int ROBIN = 21;
  static final int SOM = 22;
  static final int ALASKA = 23;
  static final int GOOD = 24;
  static final int MOLL = 25;
  static final int IMOLL = 26;
  static final int HAMMER = 27;
  static final int WAGIV = 28;
  static final int WAGVII = 29;
  static final int OBEQA = 30;
  static final int USDEF = 99;

  static final int DATMCT = 20;

  static final double PI = 3.141592653589793238;
  static final double HALF_PI = PI*0.5;
  static final double TWO_PI = PI*2.0;
  static final double EPSLNI = 1.0e-10;
  static final double R2D = 57.2957795131;
  static final double D2R = 1.745329251994328e-2;
  static final double S2R = 4.848136811095359e-6;
  static final double EPSLN = 1.0e-10;

  static final int MAX_VAL = 4;
  static final long MAXLONG = 2147483647;
  static final double DBLLONG = 4.61168601e18;


/*******************************************************************************
NAME                           SPHDZ

PURPOSE:        This function assigns values to the semimajor axis, semiminor
                axis, and radius of sphere.  If the datum code is negative,
                the first two values in the parameter array (parm) are used
                to define the values as follows:

                --If parm[0] is a non-zero value and parm[1] is greater than
                  one, the semimajor axis and radius are set to parm[0] and
                  the semiminor axis is set to parm[1].

                --If parm[0] is nonzero and parm[1] is greater than zero but
                  less than or equal to one, the semimajor axis and radius
                  are set to parm[0] and the semiminor axis is computed
                  from the eccentricity squared value parm[1].  This
                  algorithm is given below.

                --If parm[0] is nonzero and parm[1] is equal to zero, the
                  semimajor axis, radius, and semiminor axis are set to
                  parm[0].

                --If parm[0] equals zero and parm[1] is greater than zero,
                  the default Clarke 1866 is used to assign values to the
                  semimajor axis, radius and semiminor axis.

                --If parm[0] and parm[1] equals zero, the semimajor axis
                  and radius are set to 6370997.0 (This value is represented
                  as the last value in the datum code array) and the
                  semiminor axis is set to zero.

                if a datum code is zero or greater, the semimajor and
                semiminor axis are defined by the datum code as found
                in Table A and the radius is set to 6370997.0.  If the
                datum code is greater than DATMCT the default datum,
                Clarke 1866, is used to define the semimajor
                and semiminor axis and radius is set to 6370997.0.

                The algorithm to define the semiminor axis using the
                eccentricity squared value is as follows:

                      semiminor = sqrt(1.0 - ES) * semimajor   where
                      ES = eccentricity squared

                Table A:
                                SUPPORTED SPHEROIDS

                 0: Clarke 1866 (default)        1: Clarke 1880
                 2: Bessel                       3: International 1967
                 4: International 1909           5: WGS 72
                 6: Everest                      7: WGS 66
                 8: GRS 1980                     9: Airy
                10: Modified Everest            11: Modified Airy
                12: WGS 84                      13: Southeast Asia
                14: Australian National         15: Krassovsky
                16: Hough                       17: Mercury 1960
                18: Modified Mercury 1968       19: Sphere of Radius
                                                    6370997 meters

PROGRAMMER              DATE
----------              ----
T. Mittan             MARCH, 1993

ALGORITHM REFERENCES

1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
    Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
    State Government Printing Office, Washington D.C., 1987.

2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
    U.S. Geological Survey Professional Paper 1453 , United State Government
    Printing Office, Washington D.C., 1989.
*******************************************************************************/

static double major_data[] = {6378206.4, 6378249.145, 6377397.155, 6378157.5,
                              6378388.0, 6378135.0, 6377276.3452, 6378145.0,
                              6378137.0, 6377563.396, 6377304.063, 6377340.189,
                              6378137.0, 6378155.0, 6378160.0, 6378245.0,
                              6378270.0, 6378166.0, 6378150.0, 6370997.0};

static double minor_data[] = {6356583.8, 6356514.86955, 6356078.96284, 6356772.2,
                              6356911.94613, 6356750.519915, 6356075.4133,
                              6356759.769356, 6356752.31414, 6356256.91,
                              6356103.039, 6356034.448, 6356752.314245,
                              6356773.3205, 6356774.719, 6356863.0188,
                              6356794.343479, 6356784.283666, 6356768.337303,
                              6370997.0};


/* Finds the correct ellipsoid axis
---------------------------------*/

public static int sphdz( long isph,        // spheroid code number
                         double[] parm,    // projection parameters
                         double[] major,     // major axis
                         double[] minor,     // minor axis
                         double[] radius  )  // radius
{

double r_radius;
double r_major;
double t_major;         // temporary major axis
double r_minor;
double t_minor;         // temporary minor axis
long jsph;              // spheroid code number

if (isph < 0)
   {
   t_major = Math.abs(parm[0]);
   t_minor = Math.abs(parm[1]);

   if (t_major  > 0.0)
     {
     if (t_minor > 1.0)
        {
        r_major = t_major;
        r_minor = t_minor;
        r_radius = t_major;
        }
     else
     if (t_minor > 0.0)
        {
        r_major = t_major;
        r_radius = t_major;
        r_minor = (Math.sqrt(1.0 - t_minor)) * t_major;
        }
     else
        {
        r_major = t_major;
        r_radius = t_major;
        r_minor = t_major;
        }
     }
   else
   if (t_minor > 0.0)   /* t_major = 0 */
     {
     r_major = major_data[0];
     r_radius = major_data[0];
     r_minor = minor_data[0];
     }
   else
     {
     r_major = major_data[DATMCT - 1];
     r_radius = major_data[DATMCT - 1];
     r_minor = 6370997.0;
     }
  }
else            /* isph >= 0 */
  {
  jsph = Math.abs(isph);
  if (jsph > 19)
     {
     // p_error("Invalid spheroid selection","INFORMATIONAL");
     // p_error("Reset to 0","INFORMATIONAL");
     isph = 1;
     jsph = 0;
     }
  r_major = major_data[(int)jsph];
  r_minor = minor_data[(int)jsph];
  r_radius = major_data[DATMCT - 1];
  }

  major[0] = r_major;
  minor[0] = r_minor;
  radius[0] = r_radius;

return(0);
}

/*******************************************************************************
NAME                            PAKSZ

PURPOSE:        This function converts a packed DMS angle to seconds.  The
                standard packed DMS format is:

                degrees * 1000000 + minutes * 1000 + seconds

                Example:        ang = 120025045.25 yields
                                deg = 120
                                min = 25
                                sec = 45.25

                The algorithm used for the conversion is as follows:

                1.  The absolute value of the angle is used.

                2.  The degrees are separated out:
                    deg = ang/1000000   (fractional portion truncated)

                3.  The minutes are separated out:
                    min = (ang - deg * 1000000) / 1000     (fractional
                                                        portion truncated)

                4.  The seconds are then computed:
                    sec = ang - deg * 1000000 - min * 1000

                5.  The total angle in seconds is computed:
                    sec = deg * 3600.0 + min * 60.0 + sec

                6.  The sign of sec is set to that of the input angle.


PROGRAMMER              DATE
----------              ----
T. Mittan             MARCH, 1993

ALGORITHM REFERENCES

1.  Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
    Survey Proffesional Paper 1395 (Supersedes USGS Bulletin 1532), United
    State Government Printing Office, Washington D.C., 1987.

2.  Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
    U.S. Geological Survey Professional Paper 1453 , United State Government
    Printing Office, Washington D.C., 1989.
*******************************************************************************/

/* Convert DMS packed angle into deg
----------------------------------*/

static int paksz( double ang,        // angle in DMS
                  double[] Ddeg        // fractional degrees
                              )
{

double fac;             /* sign flag                    */
double deg;             /* degree variable              */
double min;             /* minute variable              */
double sec;             /* seconds variable             */
double tmp;             /* temporary variable           */
long i;                 /* temporary variable           */


if (ang < 0.0)
   fac = -1;
else
   fac = 1;

/* find degrees
-------------*/
sec = Math.abs(ang);
tmp = 1000000.0;
i = (long) (sec/tmp);
if (i > 360)
  {
  //p_error("Illegal DMS field","paksz-deg");
  return(-1);
  }
else
  deg = i;

/* find minutes
-------------*/
sec = sec - deg * tmp;
tmp = 1000;
i = (long) (sec / tmp);
if (i > 60)
  {
  //p_error("Illegal DMS field","paksz-min");
  return(-1);
  }
else
  min = i;

/* find seconds
-------------*/
sec = sec - min * tmp;
if (sec > 60)
  {
  //p_error("Illegal DMS field","paksz-sec");
  return(-1);
  }
else
  sec = fac * (deg * 3600.0 + min * 60.0 + sec);
deg = sec / 3600.0;

Ddeg[0] = deg;
return(0);
}

/* Function to return the sign of an argument
  ------------------------------------------*/
public static int sign( double x
                                  )
{
  if (x < 0.0 ) {
    return(-1);
  }
  else {
    return(1);
  }
}

/* Function to adjust a longitude angle to range from -180 to 180 radians
   added if statments
  -----------------------------------------------------------------------*/

public static double[] adjust_lon( double[] x     // array of angles in radians
                                              )
{

long temp;
long count = 0;

int length = x.length;

for ( int ii = 0; ii < length; ii++ )
{
   for(;;)
   {
     if (Math.abs(x[ii])<=PI)
        break;
     else
     if (((long) Math.abs(x[ii] / PI)) < 2)
        x[ii] = x[ii]-(sign(x[ii]) *TWO_PI);
     else
     if (((long) Math.abs(x[ii] / TWO_PI)) < MAXLONG)
        {
        x[ii] = x[ii]-(((long)(x[ii] / TWO_PI))*TWO_PI);
        }
     else
     if (((long) Math.abs(x[ii] / (MAXLONG * TWO_PI))) < MAXLONG)
        {
        x[ii] = x[ii]-(((long)(x[ii] / (MAXLONG * TWO_PI))) * (TWO_PI * MAXLONG));
        }
     else
     if (((long) Math.abs(x[ii] / (DBLLONG * TWO_PI))) < MAXLONG)
        {
        x[ii] = x[ii]-(((long)(x[ii] / (DBLLONG * TWO_PI))) * (TWO_PI * DBLLONG));
        }
     else
        x[ii] = x[ii]-(sign(x[ii]) *TWO_PI);
     count++;
     if (count > MAX_VAL)
        break;
   }
}

return(x);
}

public static double adjust_lon( double x     //  angle in radians
                                           )
{

long temp;
long count = 0;

   for(;;)
   {
     if (Math.abs(x)<=PI)
        break;
     else
     if (((long) Math.abs(x / PI)) < 2)
        x = x - (sign(x) *TWO_PI);
     else
     if (((long) Math.abs(x / TWO_PI)) < MAXLONG)
        {
        x = x-(((long)(x / TWO_PI))*TWO_PI);
        }
     else
     if (((long) Math.abs(x / (MAXLONG * TWO_PI))) < MAXLONG)
        {
        x = x - (((long)(x / (MAXLONG * TWO_PI))) * (TWO_PI * MAXLONG));
        }
     else
     if (((long) Math.abs(x / (DBLLONG * TWO_PI))) < MAXLONG)
        {
        x = x - (((long)(x / (DBLLONG * TWO_PI))) * (TWO_PI * DBLLONG));
        }
     else
        x = x - (sign(x) *TWO_PI);
     count++;
     if (count > MAX_VAL)
        break;
   }

return(x);
}

public static void sincos( double[] val,
                           double[] sin_val,
                           double[] cos_val
                                             )
{

  int length = val.length;

  for ( int ii = 0; ii < length; ii++ )
  {
    sin_val[ii] = Math.sin(val[ii]);
    cos_val[ii] = Math.cos(val[ii]);
  }

  return;
}

public static void sincos( double val,
                           Double sin_val,
                           Double cos_val
                                             )
{


    double sin = Math.sin(val);
    double cos = Math.cos(val);

    sin_val = new Double( sin );
    cos_val = new Double( cos );

  return;
}


/* Function to eliminate roundoff errors in asin
----------------------------------------------*/
public static double asinz ( double con
                                         )
{
 if (Math.abs(con) > 1.0)
 {
   if (con > 1.0) {
     con = 1.0;
   }
   else {
     con = -1.0;
   }
 }

 con = Math.asin(con);

 return con;
}

/* Function to compute the constant e4 from the input of the eccentricity
   of the spheroid, x.  This constant is used in the Polar Stereographic
   projection.
--------------------------------------------------------------------*/
public static double e4fn( double x         //eccentricity
                                     )
{
 double con;
 double com;
 con = 1.0 + x;
 com = 1.0 - x;
 return (Math.sqrt((Math.pow(con,con))*(Math.pow(com,com))));
}

/* Function to compute the constant small m which is the radius of
   a parallel of latitude, phi, divided by the semimajor axis.
---------------------------------------------------------------*/
public static double msfnz ( double eccent,
                             double sinphi,
                             double cosphi
                                            )
{
  double con;

  con = eccent * sinphi;
  return((cosphi / (Math.sqrt (1.0 - con * con))));
}

/* Function to compute the constant small t for use in the forward
   computations in the Lambert Conformal Conic and the Polar
   Stereographic projections.
--------------------------------------------------------------*/
public static double tsfnz( double eccent,     // Eccentricity of the spheroid
                            double phi,        // Latitude phi
                            double sinphi      // Sine of the latitude
                                            )
{
  double con;
  double com;

  con = eccent * sinphi;
  com = .5 * eccent;
  con = Math.pow(((1.0 - con) / (1.0 + con)),com);
  return (Math.tan(.5 * (HALF_PI - phi))/con);
}

/* Function to compute the latitude angle, phi2, for the inverse of the
   Lambert Conformal Conic and Polar Stereographic projections.
----------------------------------------------------------------*/
public static double phi2z( double eccent,       // Spheroid eccentricity
                            double ts            // Constant value t
                                           )
{
double eccnth;
double phi;
double con;
double dphi;
double sinpi;
int i;
  eccnth = .5 * eccent;
  phi = HALF_PI - 2 * Math.atan(ts);
  for (i = 0; i <= 15; i++)
  {
    sinpi = Math.sin(phi);
    con = eccent * sinpi;
    dphi = HALF_PI - 2 * Math.atan(ts *(Math.pow(((1.0 - con)/(1.0 + con)),eccnth))) -
           phi;
    phi += dphi;
    if (Math.abs(dphi) <= .0000000001)
       return(phi);
  }

  return Double.NaN;
}

} /* end class */

 

Ads help maintain this website.