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

net.acesinc.data.binner.GeoTileBinner Maven / Gradle / Ivy

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package net.acesinc.data.binner;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author andrewserff
 */
public class GeoTileBinner extends Binner {

    private static Logger log = LoggerFactory.getLogger(GeoTileBinner.class);

    public static int MAX_LEVEL_DEFAULT = 10;
    private int maxLevel = MAX_LEVEL_DEFAULT;
    private String latFieldName = "lat";
    private String lonFieldName = "lon";

    public GeoTileBinner(String countName) {
        super(countName);
    }

    public GeoTileBinner(String countName, int maxLevel) {
        this(countName, countName, maxLevel);
    }

    public GeoTileBinner(String countName, String dataFieldName) {
        super(countName, dataFieldName);
    }

    public GeoTileBinner(String countName, String dataFieldName, int maxLevel) {
        super(countName, dataFieldName);
        this.maxLevel = maxLevel;
    }

    /**
     *
     * @param countName
     * @param dataFieldName
     * @param maxLevel
     * @param latFieldName Used if the provided value is a Map. If not provided, defaults to "lat"
     * @param lonFieldName Used if the provided value is a Map. If not provided, defaults to "lon"
     */
    public GeoTileBinner(String countName, String dataFieldName, int maxLevel, String latFieldName, String lonFieldName) {
        super(countName, dataFieldName);
        this.maxLevel = maxLevel;
        this.latFieldName = latFieldName;
        this.lonFieldName = lonFieldName;
    }

    @Override
    protected List generateBinNamesForData(Object value) {
        //we should support inbound data in the formats: List (lat, long)
        List binNames = new ArrayList<>();

        Double lat = null;
        Double lon = null;
        
        Object latObj = null;
        Object lonObj = null;
        if (List.class.isAssignableFrom(value.getClass())) {
            List list = (List) value;
            if (list.size() == 2) {
                latObj = list.get(0);
                lonObj = list.get(1);

            } else {
                //why would there be less or more than two? got me! get out of here!
            }
        } else if (Map.class.isAssignableFrom(value.getClass())) {
            //hopefully this means there is a lat and lon key
            Map map = (Map) value;
            latObj = map.get(latFieldName);
            lonObj = map.get(lonFieldName); 
        }

        //now we assume those two values are doubles...but are they?
        if (Double.class.isAssignableFrom(latObj.getClass()) && Double.class.isAssignableFrom(lonObj.getClass())) {
            lat = (Double) latObj;
            lon = (Double) lonObj;
        } else if (String.class.isAssignableFrom(latObj.getClass()) && String.class.isAssignableFrom(lonObj.getClass())) {
            //maybe they wrapped the double in a string?
            lat = Double.valueOf(latObj.toString());
            lon = Double.valueOf(lonObj.toString());
        } else {
            //ya...no clue...
        }

        if (lat != null && lon != null) {
            //Now that we have the lat/lon, we need to determin what tile coordinates that lat/lon falls in at each zoom level
            //TODO...
            for (int zoomLevel = 0; zoomLevel < maxLevel; zoomLevel++) {
                //calculate x and y at each zoom level
                binNames.add(getBinName() + "." + getTileNumber(lat, lon, zoomLevel));
            }
        }

        if (binNames.isEmpty()) {
            log.warn("Provided value for count [ " + getBinName() + " ] is not a valid format. Please provide an array/list of Double values in lat, lon order");
        }
        return binNames;
    }

    //from http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Java
    protected String getTileNumber(final double lat, final double lon, final int zoom) {
        int xtile = (int) Math.floor((lon + 180) / 360 * (1 << zoom));
        int ytile = (int) Math.floor((1 - Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI) / 2 * (1 << zoom));
        if (xtile < 0) {
            xtile = 0;
        }
        if (xtile >= (1 << zoom)) {
            xtile = ((1 << zoom) - 1);
        }
        if (ytile < 0) {
            ytile = 0;
        }
        if (ytile >= (1 << zoom)) {
            ytile = ((1 << zoom) - 1);
        }
        return ("" + zoom + "-" + xtile + "-" + ytile);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy