/**
   * Returns a geographic Sector which bounds the specified UTM rectangle. The UTM rectangle is
   * located in specified UTM zone and hemisphere.
   *
   * @param zone the UTM zone.
   * @param hemisphere the UTM hemisphere, either {@link gov.nasa.worldwind.avlist.AVKey#NORTH} or
   *     {@link gov.nasa.worldwind.avlist.AVKey#SOUTH}.
   * @param minEasting the minimum UTM easting, in meters.
   * @param maxEasting the maximum UTM easting, in meters.
   * @param minNorthing the minimum UTM northing, in meters.
   * @param maxNorthing the maximum UTM northing, in meters.
   * @return a Sector that bounds the specified UTM rectangle.
   * @throws IllegalArgumentException if <code>zone</code> is outside the range 1-60, if <code>
   *     hemisphere</code> is null, or if <code>hemisphere</code> is not one of {@link
   *     gov.nasa.worldwind.avlist.AVKey#NORTH} or {@link gov.nasa.worldwind.avlist.AVKey#SOUTH}.
   */
  public static Sector fromUTMRectangle(
      int zone,
      String hemisphere,
      double minEasting,
      double maxEasting,
      double minNorthing,
      double maxNorthing) {
    if (zone < 1 || zone > 60) {
      throw new IllegalArgumentException("ZoneIsInvalid");
    }

    if (!AVKey.NORTH.equals(hemisphere) && !AVKey.SOUTH.equals(hemisphere)) {
      throw new IllegalArgumentException("HemisphereIsInvalid");
    }

    LatLon ll = UTMCoord.locationFromUTMCoord(zone, hemisphere, minEasting, minNorthing);
    LatLon lr = UTMCoord.locationFromUTMCoord(zone, hemisphere, maxEasting, minNorthing);
    LatLon ur = UTMCoord.locationFromUTMCoord(zone, hemisphere, maxEasting, maxNorthing);
    LatLon ul = UTMCoord.locationFromUTMCoord(zone, hemisphere, minEasting, maxNorthing);

    return boundingSector(Arrays.asList(ll, lr, ur, ul));
  }
  /**
   * The function Convert_UPS_To_MGRS converts UPS (hemisphere, easting, and northing) coordinates
   * to an MGRS coordinate string according to the current ellipsoid parameters. If any errors
   * occur, the error code(s) are returned by the function, otherwise MGRS_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
   * @param Precision Precision level of MGRS string
   * @return error value
   */
  private long convertUPSToMGRS(
      String Hemisphere, Double Easting, Double Northing, long Precision) {
    double false_easting; /* False easting for 2nd letter                 */
    double false_northing; /* False northing for 3rd letter                */
    double grid_easting; /* Easting used to derive 2nd letter of MGRS    */
    double grid_northing; /* Northing used to derive 3rd letter of MGRS   */
    int ltr2_low_value; /* 2nd letter range - low number                */
    long[] letters = new long[MGRS_LETTERS]; /* Number location of 3 letters in alphabet     */
    double divisor;
    int index;
    long error_code = MGRS_NO_ERROR;

    if (!AVKey.NORTH.equals(Hemisphere) && !AVKey.SOUTH.equals(Hemisphere))
      error_code |= MGRS_HEMISPHERE_ERROR;
    if ((Easting < MIN_EAST_NORTH) || (Easting > MAX_EAST_NORTH)) error_code |= MGRS_EASTING_ERROR;
    if ((Northing < MIN_EAST_NORTH) || (Northing > MAX_EAST_NORTH))
      error_code |= MGRS_NORTHING_ERROR;
    if ((Precision < 0) || (Precision > MAX_PRECISION)) error_code |= MGRS_PRECISION_ERROR;

    if (error_code == MGRS_NO_ERROR) {
      divisor = Math.pow(10.0, (5 - Precision));
      Easting = roundMGRS(Easting / divisor) * divisor;
      Northing = roundMGRS(Northing / divisor) * divisor;

      if (AVKey.NORTH.equals(Hemisphere)) {
        if (Easting >= TWOMIL) letters[0] = LETTER_Z;
        else letters[0] = LETTER_Y;

        index = (int) letters[0] - 22;
        //                ltr2_low_value = UPS_Constant_Table.get(index).ltr2_low_value;
        //                false_easting = UPS_Constant_Table.get(index).false_easting;
        //                false_northing = UPS_Constant_Table.get(index).false_northing;
        ltr2_low_value = (int) upsConstants[index][1];
        false_easting = (double) upsConstants[index][4];
        false_northing = (double) upsConstants[index][5];
      } else // AVKey.SOUTH.equals(Hemisphere)
      {
        if (Easting >= TWOMIL) letters[0] = LETTER_B;
        else letters[0] = LETTER_A;

        //                ltr2_low_value = UPS_Constant_Table.get((int) letters[0]).ltr2_low_value;
        //                false_easting = UPS_Constant_Table.get((int) letters[0]).false_easting;
        //                false_northing = UPS_Constant_Table.get((int) letters[0]).false_northing;
        ltr2_low_value = (int) upsConstants[(int) letters[0]][1];
        false_easting = (double) upsConstants[(int) letters[0]][4];
        false_northing = (double) upsConstants[(int) letters[0]][5];
      }

      grid_northing = Northing;
      grid_northing = grid_northing - false_northing;
      letters[2] = (int) (grid_northing / ONEHT);

      if (letters[2] > LETTER_H) letters[2] = letters[2] + 1;

      if (letters[2] > LETTER_N) letters[2] = letters[2] + 1;

      grid_easting = Easting;
      grid_easting = grid_easting - false_easting;
      letters[1] = (int) ltr2_low_value + ((int) (grid_easting / ONEHT));

      if (Easting < TWOMIL) {
        if (letters[1] > LETTER_L) letters[1] = letters[1] + 3;

        if (letters[1] > LETTER_U) letters[1] = letters[1] + 2;
      } else {
        if (letters[1] > LETTER_C) letters[1] = letters[1] + 2;

        if (letters[1] > LETTER_H) letters[1] = letters[1] + 1;

        if (letters[1] > LETTER_L) letters[1] = letters[1] + 3;
      }

      makeMGRSString(0, letters, Easting, Northing, Precision);
    }
    return (error_code);
  }