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

hivemall.utils.geospatial.GeoSpatialUtils Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package hivemall.utils.geospatial;

import static hivemall.utils.math.MathUtils.sec;
import static java.lang.Math.PI;
import static java.lang.Math.atan;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.floor;
import static java.lang.Math.log;
import static java.lang.Math.pow;
import static java.lang.Math.sin;
import static java.lang.Math.sinh;
import static java.lang.Math.sqrt;
import static java.lang.Math.tan;
import static java.lang.Math.toDegrees;
import static java.lang.Math.toRadians;

import javax.annotation.Nonnegative;

public final class GeoSpatialUtils {

    public static final double MAX_LATITUDE = 85.0511d;
    public static final double MIN_LATITUDE = -85.0511d;

    private GeoSpatialUtils() {}

    public static int lon2tilex(final double lon, @Nonnegative final int zoom) {
        if (lon < -180.d || lon > 180.d) {
            throw new IllegalArgumentException("Longitude must be in range [-180,+180]: " + lon);
        }
        return (int) floor((lon + 180.d) / 360.d * (1 << zoom));
    }

    public static int lat2tiley(final double lat, @Nonnegative final int zoom) {
        if (lat < MIN_LATITUDE || lat > MAX_LATITUDE) {
            throw new IllegalArgumentException("Latitude must be in range [-85.0511,+85.0511]: "
                    + lat + "\nSee http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames");
        }
        double lat_rad = toRadians(lat);
        int n = 1 << zoom;
        return (int) floor((1.d - log(tan(lat_rad) + sec(lat_rad)) / PI) / 2.d * n);
    }

    public static double tilex2lon(final int x, @Nonnegative final int zoom) {
        return x / pow(2.d, zoom) * 360.d - 180.d;
    }

    public static double tiley2lat(final int y, @Nonnegative final int zoom) {
        double n = PI - (2.d * PI * y) / pow(2.d, zoom);
        return toDegrees(atan(sinh(n)));
    }

    /**
     * @link https://en.wikipedia.org/wiki/Tiled_web_map#Tile_numbering_schemes
     */
    public static long tile(final double lat, final double lon, @Nonnegative final int zoom) {
        int xtile = lon2tilex(lon, zoom);
        int ytile = lat2tiley(lat, zoom);
        long n = 1L << zoom; // 2^z
        return xtile + (n * ytile);
    }

    public static int tiles(final int zoom) {
        return 1 << (zoom * 2); // 2^2z
    }

    /**
     * Return a Haversine distance in Kilometers between two points.
     * 
     * @link http://www.movable-type.co.uk/scripts/latlong.html
     * @link http://rosettacode.org/wiki/Haversine_formula#Java
     * @return distance between two points in Kilometers
     */
    public static double haversineDistance(final double lat1, final double lon1, final double lat2,
            final double lon2) {
        double R = 6371.0d; // Radius of the earth in Km
        double dLat = toRadians(lat2 - lat1); // deg2rad below
        double dLon = toRadians(lon2 - lon1);
        double sinDLat = sin(dLat / 2.d);
        double sinDLon = sin(dLon / 2.d);
        double a =
                sinDLat * sinDLat + cos(toRadians(lat1)) * cos(toRadians(lat2)) * sinDLon * sinDLon;
        double c = 2.d * atan2(sqrt(a), sqrt(1.d - a));
        return R * c; // Distance in Km
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy