/* * Licensed to GraphHopper GmbH under one or more contributor * license agreements. See the NOTICE file distributed with this work for * additional information regarding copyright ownership. * * GraphHopper GmbH 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 com.graphhopper.geohash; import com.graphhopper.util.shapes.BBox; import com.graphhopper.util.shapes.GHPoint; /** * This class maps lat,lon to a (tile)number unlike SpatialKeyAlgo. * <p> * * @author Peter Karich */ // A 4*3 precision linear key will look like // // |----|----|----|----| // | 0| 1| 2| 3| // |----|----|----|----| // lat | 4| 5| 6| 7| // |----|----|----|----| // | 8| 9| 10| 11| // |----|----|----|----| // // lon public class LinearKeyAlgo implements KeyAlgo { private static final double C = 1 - 1e-15; private final int latUnits, lonUnits; private BBox bounds; private double latDelta, lonDelta; public LinearKeyAlgo(int latUnits, int lonUnits) { this.latUnits = latUnits; this.lonUnits = lonUnits; setWorldBounds(); } @Override public LinearKeyAlgo setBounds(double minLonInit, double maxLonInit, double minLatInit, double maxLatInit) { bounds = new BBox(minLonInit, maxLonInit, minLatInit, maxLatInit); latDelta = (bounds.maxLat - bounds.minLat) / latUnits; lonDelta = (bounds.maxLon - bounds.minLon) / lonUnits; return this; } public LinearKeyAlgo setBounds(BBox bounds) { setBounds(bounds.minLon, bounds.maxLon, bounds.minLat, bounds.maxLat); return this; } protected void setWorldBounds() { setBounds(-180, 180, -90, 90); } @Override public long encode(GHPoint coord) { return encode(coord.lat, coord.lon); } /** * Take latitude and longitude as input. * <p> * * @return the linear key */ @Override public final long encode(double lat, double lon) { lat = Math.min(Math.max(lat, bounds.minLat), bounds.maxLat); lon = Math.min(Math.max(lon, bounds.minLon), bounds.maxLon); // introduce a minor correction to round to lower grid entry! long latIndex = (long) ((lat - bounds.minLat) / latDelta * C); long lonIndex = (long) ((lon - bounds.minLon) / lonDelta * C); return latIndex * lonUnits + lonIndex; } /** * This method returns latitude and longitude via latLon - calculated from specified linearKey * <p> * * @param linearKey is the input */ @Override public final void decode(long linearKey, GHPoint latLon) { double lat = linearKey / lonUnits * latDelta + bounds.minLat; double lon = linearKey % lonUnits * lonDelta + bounds.minLon; latLon.lat = lat + latDelta / 2; latLon.lon = lon + lonDelta / 2; } public double getLatDelta() { return latDelta; } public double getLonDelta() { return lonDelta; } }