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

src.gov.nasa.worldwind.geom.coords.UPSCoordConverter Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show newest version
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */

/********************************************************************/
/* RSC IDENTIFIER: UPS
 *
 *
 * ABSTRACT
 *
 *    This component provides conversions between geodetic (latitude
 *    and longitude) coordinates and Universal Polar Stereographic (UPS)
 *    projection (hemisphere, easting, and northing) coordinates.
 *
 *
 * ERROR HANDLING
 *
 *    This component checks parameters for valid values.  If an
 *    invalid value is found the error code is combined with the
 *    current error code using the bitwise or.  This combining allows
 *    multiple error codes to be returned. The possible error codes
 *    are:
 *
 *         UPS_NO_ERROR           : No errors occurred in function
 *         UPS_LAT_ERROR          : Latitude outside of valid range
 *                                   (North Pole: 83.5 to 90,
 *                                    South Pole: -79.5 to -90)
 *         UPS_LON_ERROR          : Longitude outside of valid range
 *                                   (-180 to 360 degrees)
 *         UPS_HEMISPHERE_ERROR   : Invalid hemisphere ('N' or 'S')
 *         UPS_EASTING_ERROR      : Easting outside of valid range,
 *                                   (0 to 4,000,000m)
 *         UPS_NORTHING_ERROR     : Northing outside of valid range,
 *                                   (0 to 4,000,000m)
 *         UPS_A_ERROR            : Semi-major axis less than or equal to zero
 *         UPS_INV_F_ERROR        : Inverse flattening outside of valid range
 *								  	               (250 to 350)
 *
 *
 * REUSE NOTES
 *
 *    UPS is intended for reuse by any application that performs a Universal
 *    Polar Stereographic (UPS) projection.
 *
 *
 * REFERENCES
 *
 *    Further information on UPS can be found in the Reuse Manual.
 *
 *    UPS originated from :  U.S. Army Topographic Engineering Center
 *                           Geospatial Information Division
 *                           7701 Telegraph Road
 *                           Alexandria, VA  22310-3864
 *
 *
 * LICENSES
 *
 *    None apply to this component.
 *
 *
 * RESTRICTIONS
 *
 *    UPS has no restrictions.
 *
 *
 * ENVIRONMENT
 *
 *    UPS was tested and certified in the following environments:
 *
 *    1. Solaris 2.5 with GCC version 2.8.1
 *    2. Windows 95 with MS Visual C++ version 6
 *
 *
 * MODIFICATIONS
 *
 *    Date              Description
 *    ----              -----------
 *    06-11-95          Original Code
 *    03-01-97          Original Code
 *
 *
 */

package gov.nasa.worldwind.geom.coords;

import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.globes.Globe;

/**
 * Ported to Java from the NGA GeoTrans ups.c and ups.h code - Feb 12, 2007 4:52:59 PM
 *
 * @author Garrett Headley, Patrick Murris
 * @version $Id: UPSCoordConverter.java 1171 2013-02-11 21:45:02Z dcollins $
 */
public class UPSCoordConverter
{
    public static final int UPS_NO_ERROR = 0x0000;
    private static final int UPS_LAT_ERROR = 0x0001;
    private static final int UPS_LON_ERROR = 0x0002;
    public static final int UPS_HEMISPHERE_ERROR = 0x0004;
    public static final int UPS_EASTING_ERROR = 0x0008;
    public static final int UPS_NORTHING_ERROR = 0x0010;
    private static final int UPS_A_ERROR = 0x0020;
    private static final int UPS_INV_F_ERROR = 0x0040;

    private static final double PI = 3.14159265358979323;
    private static final double MAX_LAT = (PI * 90) / 180.0;             // 90 degrees in radians
    // Min and max latitude values accepted
    private static final double MIN_NORTH_LAT = 72 * PI / 180.0;       // 83.5
    private static final double MIN_SOUTH_LAT = -72 * PI / 180.0;      // -79.5

    private static final double MAX_ORIGIN_LAT = (81.114528 * PI) / 180.0;
    private static final double MIN_EAST_NORTH = 0;
    private static final double MAX_EAST_NORTH = 4000000;

    private double UPS_Origin_Latitude = MAX_ORIGIN_LAT;  /*set default = North Hemisphere */
    private double UPS_Origin_Longitude = 0.0;

    /* Ellipsoid Parameters, default to WGS 84  */
    private final Globe globe;
    private double UPS_a = 6378137.0;          /* Semi-major axis of ellipsoid in meters   */
    private double UPS_f = 1 / 298.257223563;  /* Flattening of ellipsoid  */
    private double UPS_False_Easting = 2000000.0;
    private double UPS_False_Northing = 2000000.0;
    private double false_easting = 0.0;
    private double false_northing = 0.0;
    private double UPS_Easting = 0.0;
    private double UPS_Northing = 0.0;

    private double Easting = 0.0;
    private double Northing = 0.0;
    private String Hemisphere = AVKey.NORTH;
    private double Latitude = 0.0;
    private double Longitude = 0.0;

    private PolarCoordConverter polarConverter = new PolarCoordConverter();

    UPSCoordConverter(Globe globe)
    {
        this.globe = globe;
        if (globe != null)
        {
            double a = globe.getEquatorialRadius();
            double f = (globe.getEquatorialRadius() - globe.getPolarRadius()) / globe.getEquatorialRadius();
            setUPSParameters(a, f);
        }
    }

    /**
     * The function SetUPSParameters receives the ellipsoid parameters and sets the corresponding state variables. If
     * any errors occur, the error code(s) are returned by the function, otherwise UPS_NO_ERROR is returned.
     *
     * @param a Semi-major axis of ellipsoid in meters
     * @param f Flattening of ellipsoid
     *
     * @return error code
     */
    public long setUPSParameters(double a, double f)
    {
        double inv_f = 1 / f;

        if (a <= 0.0)
        { /* Semi-major axis must be greater than zero */
            return UPS_A_ERROR;
        }
        if ((inv_f < 250) || (inv_f > 350))
        { /* Inverse flattening must be between 250 and 350 */
            return UPS_INV_F_ERROR;
        }

        UPS_a = a;
        UPS_f = f;

        return (UPS_NO_ERROR);
    }

    /**
     * The function convertGeodeticToUPS converts geodetic (latitude and longitude) coordinates to UPS (hemisphere,
     * easting, and northing) coordinates, according to the current ellipsoid parameters. If any errors occur, the error
     * code(s) are returned by the function, otherwide UPS_NO_ERROR is returned.
     *
     * @param latitude  Latitude in radians
     * @param longitude Longitude in radians
     *
     * @return error code
     */
    public long convertGeodeticToUPS(double latitude, double longitude)
    {
        if ((latitude < -MAX_LAT) || (latitude > MAX_LAT))
        {   /* latitude out of range */
            return UPS_LAT_ERROR;
        }
        if ((latitude < 0) && (latitude > MIN_SOUTH_LAT))
            return UPS_LAT_ERROR;
        if ((latitude >= 0) && (latitude < MIN_NORTH_LAT))
            return UPS_LAT_ERROR;

        if ((longitude < -PI) || (longitude > (2 * PI)))
        {  /* slam out of range */
            return UPS_LON_ERROR;
        }

        if (latitude < 0)
        {
            UPS_Origin_Latitude = -MAX_ORIGIN_LAT;
            Hemisphere = AVKey.SOUTH;
        }
        else
        {
            UPS_Origin_Latitude = MAX_ORIGIN_LAT;
            Hemisphere = AVKey.NORTH;
        }

        polarConverter.setPolarStereographicParameters(UPS_a, UPS_f,
            UPS_Origin_Latitude, UPS_Origin_Longitude,
            false_easting, false_northing);

        polarConverter.convertGeodeticToPolarStereographic(latitude, longitude);

        UPS_Easting = UPS_False_Easting + polarConverter.getEasting();
        UPS_Northing = UPS_False_Northing + polarConverter.getNorthing();
        if (AVKey.SOUTH.equals(Hemisphere))
            UPS_Northing = UPS_False_Northing - polarConverter.getNorthing();

        Easting = UPS_Easting;
        Northing = UPS_Northing;

        return UPS_NO_ERROR;
    }

    /** @return Easting/X in meters */
    public double getEasting()
    {
        return Easting;
    }

    /** @return Northing/Y in meters */
    public double getNorthing()
    {
        return Northing;
    }

    /**
     * @return Hemisphere, either {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link
     *         gov.nasa.worldwind.avlist.AVKey#SOUTH}.
     */
    public String getHemisphere()
    {
        return Hemisphere;
    }

    /**
     * The function Convert_UPS_To_Geodetic converts UPS (hemisphere, easting, and northing) coordinates to geodetic
     * (latitude and longitude) coordinates according to the current ellipsoid parameters.  If any errors occur, the
     * error code(s) are returned by the function, otherwise UPS_NO_ERROR is returned.
     *
     * @param Hemisphere Hemisphere, either {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link
     *                   gov.nasa.worldwind.avlist.AVKey#SOUTH}.
     * @param Easting    Easting/X in meters
     * @param Northing   Northing/Y in meters
     *
     * @return error code
     */
    public long convertUPSToGeodetic(String Hemisphere, double Easting, double Northing)
    {
        long Error_Code = UPS_NO_ERROR;

        if (!AVKey.NORTH.equals(Hemisphere) && !AVKey.SOUTH.equals(Hemisphere))
            Error_Code |= UPS_HEMISPHERE_ERROR;
        if ((Easting < MIN_EAST_NORTH) || (Easting > MAX_EAST_NORTH))
            Error_Code |= UPS_EASTING_ERROR;
        if ((Northing < MIN_EAST_NORTH) || (Northing > MAX_EAST_NORTH))
            Error_Code |= UPS_NORTHING_ERROR;

        if (AVKey.NORTH.equals(Hemisphere))
            UPS_Origin_Latitude = MAX_ORIGIN_LAT;
        if (AVKey.SOUTH.equals(Hemisphere))
            UPS_Origin_Latitude = -MAX_ORIGIN_LAT;

        if (Error_Code == UPS_NO_ERROR)
        {   /*  no errors   */
            polarConverter.setPolarStereographicParameters(UPS_a,
                UPS_f,
                UPS_Origin_Latitude,
                UPS_Origin_Longitude,
                UPS_False_Easting,
                UPS_False_Northing);

            polarConverter.convertPolarStereographicToGeodetic(Easting, Northing);
            Latitude = polarConverter.getLatitude();
            Longitude = polarConverter.getLongitude();

            if ((Latitude < 0) && (Latitude > MIN_SOUTH_LAT))
                Error_Code |= UPS_LAT_ERROR;
            if ((Latitude >= 0) && (Latitude < MIN_NORTH_LAT))
                Error_Code |= UPS_LAT_ERROR;
        }
        return Error_Code;
    }

    /** @return Latitude in radians. */
    public double getLatitude()
    {
        return Latitude;
    }

    /** @return Longitude in radians. */
    public double getLongitude()
    {
        return Longitude;
    }
}






© 2015 - 2024 Weber Informatics LLC | Privacy Policy