TileIndexCalculator.java

  1. /*
  2.  * Copyright 2021 Global Crop Diversity Trust
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *   http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */

  16. package org.genesys.util;

  17. /**
  18.  * Raster grid utilities.
  19.  */
  20. public class TileIndexCalculator {

  21.     /**
  22.      * Gets the 3x3 minute grid cell zero-based index starting in the NW corner
  23.      * (-180,90) with `tile=0` and ending in the SW corner (180,-90). A 3 minute
  24.      * grid has `ncol=7200` "columns" and `nrow=3600` "rows".
  25.      *
  26.      * @param longitude the longitude
  27.      * @param latitude the latitude
  28.      * @return the cell index for a 3 degree grid
  29.      */
  30.     public static final Integer get3MinuteTileIndex(Number longitude, Number latitude) {
  31.         if (longitude == null || latitude == null)
  32.             return null;

  33.         if (longitude.doubleValue() < -180 || longitude.doubleValue() > 180)
  34.             return null;

  35.         if (latitude.doubleValue() < -90 || latitude.doubleValue() > 90)
  36.             return null;

  37.         final int columns = 7200;
  38.         final int rows = 3600;
  39.         final float xres_inv = columns / 360f;
  40.         final float yres_inv = rows / 180f;

  41.         // yx is offset by 0.5 * yd in
  42.         // https://github.com/rspatial/raster/blob/master/R/rasterFromBIL.R#L92
  43.         // I took two days to find out why math doesn't work out!
  44.         var ymax = 89.99990f; // 90.0d

  45.         int nrow;
  46.         if (latitude.intValue() == -90) {
  47.             nrow = (int) (rows) - 1;
  48.         } else if (latitude.intValue() == 90) {
  49.             nrow = 0;
  50.         } else {
  51.             nrow = (int) ((ymax - latitude.floatValue()) * yres_inv);
  52.         }

  53.         // longitude (-180:180) -> (0:columns-1)
  54.         int ncol = (int) ((longitude.floatValue() + 180f) * xres_inv);
  55.         if (longitude.intValue() == 180) {
  56.             ncol = (int) (columns - 1);
  57.         }

  58.         return nrow * columns + ncol;
  59.     }
  60. }