//
// ABINnav.java
//

/*
This source file is part of the edu.wisc.ssec.mcidas package and is
Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink,
Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden
and others.

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 edu.wisc.ssec.mcidas;

import static java.lang.Math.PI;
import static java.lang.Math.asin;
import static java.lang.Math.atan;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.sqrt;
import static java.lang.Math.tan;

/**
 * ABINnav is used to provide {@literal "navigation"} for ABIN image data.
 *
 * This code is essentially a direct port of {@code nvxabin.dlm} from McIDAS-X.
 * Note: the variable naming convention has been retained from the original
 * McIDAS-X source code.
 */
public class ABINnav extends AREAnav {

    /** Radius of satellite orbit (kilometers). */
    private static final double dh = 42164.16000000000349245965480804443359375;

    /** Convert degrees to radians. */
    private static final double deg_to_rad = PI / 180.0;

    /** Radius of the Earth at the equator (kilometers). */
    private static final double r_eq =
        6378.136999999999716237653046846389770508;

    /** Radius of the Earth at the equator squared (kilometers). */
    // note: dreq2 and r_eq2 have been kept around to conform to McIDAS-X code
    private static final double dreq2 = r_eq * r_eq;

    /** Radius of the Earth at the poles (kilometers). */
    private static final double drpo =
        6356.752300000000104773789644241333007812;

    /** Radius of the Earth at the poles squared (kilometers). */
    private static final double drpo2 = drpo * drpo;

    /** Radius of the Earth at the equator squared (kilometers). */
    // note: dreq2 and r_eq2 have been kept around to conform to McIDAS-X code
    private static final double r_eq2 = dreq2;

    /**
     * Pre-calculated constant (value is dh^2 - r_eq^2).
     *
     * @see #dh
     * @see #r_eq
     */
    private static final double d = dh * dh - r_eq2;

    private static final double FP =
        1.006802999999999892466462370066437870264;

    private boolean isEastPositive = true;

    private int itype = 1;

    /** Line offset. */
    private double loff;

    /** Column offset. */
    private double coff;

    /** Line factor. */
    private double lfac;

    /** Column factor. */
    private double cfac;

    /** Subpoint. */
    private double plon;

    /** Base resolution. */
    private double bres;

    /**
     * Initializes the ABIN navigation code with the given set of navigation
     * parameters.
     *
     * @param navblock Navigation parameters from image file.
     *
     * @throws IllegalArgumentException if {@code navblock} is not ABIN.
     */
    public ABINnav(int[] navblock) {
        if (navblock[0] != ABIN) {
            throw new IllegalArgumentException("Invalid navigation type: " +
                                               navblock[0]);
        }
        loff = navblock[1] / 100000000.0;
        coff = navblock[2] / 100000000.0;
        lfac = navblock[3] / 100000000.0;
        cfac = navblock[4] / 100000000.0;
        plon = navblock[5] / 10.0;
        bres = navblock[6];
    }

    /**
     * Convert satellite lines/elements to latitude/longitude coordinates.
     *
     * @param linele Array of line/element pairs.
     *               Where {@code linele[indexLine]} are {@literal "lines"}
     *               and {@code linele[indexEle]} are {@literal "elements"}.
     *               These coordinates must be {@literal "file"} rather than
     *               {@literal "image"} coordinates.
     *
     * @return Array of latitude/longitude pairs. {@code latlon[indexLat]} are
     *         latitudes and {@code latlon[indexLon]} are longitudes.
     */
    public double[][] toLatLon(double[][] linele) {
        final double sub_lon_radians = plon * (PI / 180.0);

        double xlin;
        double xele;
        double lamda_goes;
        double theta_goes;
        double lamda_geos;
        double theta_geos;
        double cosx;
        double cosy;
        double sinx;
        double siny;
        double c1;
        double c2;
        double sd;
        double sdd;
        double sn;
        double s1;
        double s2;
        double s3;
        double sxy;

        int length = linele[indexLine].length;
        double[][] latLons = new double[2][length];
        double[][] imageLineElems = areaCoordToImageCoord(linele);

        for (int point = 0; point < length; point++) {
            double rlin = imageLineElems[indexLine][point];
            double rele = imageLineElems[indexEle][point];

            // start img_to_ll
            xlin = 0.0;
            xele = 0.0;
            lamda_goes = 0.0;
            theta_goes = 0.0;
            lamda_geos = 0.0;
            theta_geos = 0.0;
            cosx = 0.0;
            cosy = 0.0;
            sinx = 0.0;
            siny = 0.0;

            c1 = 0.0;
            c2 = 0.0;
            sd = 0.0;
            sdd = 0.0;
            sn = 0.0;
            s1 = 0.0;
            s2 = 0.0;
            s3 = 0.0;
            sxy = 0.0;

            double xlat;
            double xlon;

            // adjust using Base RESolution
            xlin = (rlin + bres - 1) / bres;
            xele = (rele + bres - 1) / bres;

            // Intermediate coordinates (coordinates will be radians)
            theta_goes = xlin * lfac + loff;
            lamda_goes = xele * cfac + coff;

            // convert GOES to GEOS
            theta_geos = asin(sin(theta_goes) * cos(lamda_goes));
            lamda_geos = atan(tan(lamda_goes) / cos(theta_goes));

            // SIN and COS for computations below
            cosx = cos(lamda_geos);
            cosy = cos(theta_geos);
            sinx = sin(lamda_geos);
            siny = sin(theta_geos);

            c1 = dh * cosx * cosy * dh * cosx * cosy;
            c2 = (cosy * cosy + FP * siny * siny) * d;

            sdd = c1 - c2;
            if ((sdd < 0.0))  {
                xlat = Double.NaN;
                xlon = Double.NaN;
            } else {
                sd = sqrt(sdd);

                sn = (dh * cosx * cosy - sd) / (cosy * cosy + FP * siny * siny);

                s1 = dh - sn * cosx * cosy;
                s2 = sn * sinx * cosy;
                s3 = -(sn * siny);

                sxy = sqrt(s1 * s1 + (s2 * s2));
                xlon = atan(s2 / s1) + sub_lon_radians;

                xlat = atan(-(FP * s3 / sxy));

                // convert radians to degrees
                xlon = xlon * (180.0 / PI);
                xlat = xlat * (180.0 / PI);

                // Longitudes in [-180,180]
                if ((xlon > 180)) {
                    xlon = xlon - 360.0;
                }
                if ((xlon < -180)) {
                    xlon = xlon + 360.0;
                }
            }
            // end img_to_ll

            latLons[indexLat][point] = xlat;
            latLons[indexLon][point] = xlon;
        }
        return latLons;
    }

    /**
     * Convert latitudes/longitudes to satellite lines/elements.
     *
     * @param latlon Array of latitude/longitude pairs.
     *               Where {@code latlon[indexLat]} are latitudes and
     *               {@code latlon[indexLon]} are longitudes.
     *
     * @return Array of line/element pairs. {@code linele[indexLine]} are lines
     *         and {@code linele[indexEle]} are elements. These coordinates are
     *         {@literal "file"} rather than {@literal "image"} coordinates.
     */
    public double[][] toLinEle(double[][] latlon) {
        final double d_geographic_ssl = plon * deg_to_rad;

        double rlin;
        double rele;
        double d_geographic_lat;
        double d_geocentric_lat;
        double d_geographic_lon;
        double r_earth;
        double r_1;
        double r_2;
        double r_3;
        double lamda;
        double theta;

        int length = latlon[indexLat].length;
        double[][] lineEles = new double[2][length];

        for (int point = 0; point < length; point++) {
            double rlat = latlon[indexLat][point];
            double rlon = latlon[indexLon][point];
            if (!isEastPositive) {
                rlon = -rlon;
            }

            // start ll_to_img
            rlin = 0.0;
            rele = 0.0;
            d_geographic_lat = 0.0;
            d_geocentric_lat = 0.0;
            d_geographic_lon = 0.0;
            r_earth = 0.0;
            r_1 = 0.0;
            r_2 = 0.0;
            r_3 = 0.0;
            lamda = 0.0;
            theta = 0.0;

            double xlin;
            double xele;

            // Earth (Geographic) Coordinates are converted to Radians
            d_geographic_lat = rlat * deg_to_rad;
            d_geographic_lon = rlon * deg_to_rad;

            d_geocentric_lat = atan(drpo2 / dreq2 * tan(d_geographic_lat));

            r_earth = drpo / sqrt(1.0 - (dreq2 - drpo2) / dreq2 * cos(d_geocentric_lat) * cos(d_geocentric_lat));

            r_1 = dh - r_earth * cos(d_geocentric_lat) * cos(d_geographic_lon - d_geographic_ssl);

            r_2 = -(r_earth * cos(d_geocentric_lat) * sin(d_geographic_lon - d_geographic_ssl));

            r_3 = r_earth * sin(d_geocentric_lat);

            if ((r_1 > dh))  {
                xlin = Double.NaN;
                xele = Double.NaN;
            } else {
                lamda = asin(-(r_2 / sqrt(r_1 * r_1 + r_2 * r_2 + r_3 * r_3)));
                theta = atan(r_3 / r_1);

                // image line and element
                rlin = (theta - loff) / lfac;
                rele = (lamda - coff) / cfac;

                // Adjust using Base RESolution
                xlin = rlin * bres - (bres - 1);
                xele = rele * bres - (bres - 1);
            }
            // end of ll_to_img

            lineEles[indexLine][point] = xlin;
            lineEles[indexEle][point] = xele;
        }
        return imageCoordToAreaCoord(lineEles, lineEles);
    }
}

 

Ads help maintain this website.