package io.hummer.prefetch.sim.swisscom; import io.hummer.osm.model.Point; import io.hummer.osm.model.Tile; import io.hummer.prefetch.context.Location; import io.hummer.prefetch.context.NetworkQuality; import io.hummer.prefetch.context.Path.PathPoint; import io.hummer.prefetch.sim.Constants; import io.hummer.prefetch.sim.gmaps.GMapsCoordinatesConverter; import io.hummer.prefetch.sim.util.Util; import io.hummer.util.log.LogUtil; import io.hummer.util.xml.XMLUtil; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.io.File; import java.io.Serializable; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.imageio.ImageIO; import org.apache.log4j.Logger; /** * Cellular network coverage util for Swisscom. * * @author Waldemar Hummer */ public class CellularCoverage implements Serializable { protected static final long serialVersionUID = 1L; private static TiledMapSwisscom cache = new TiledMapSwisscom(); private static final String URL_PATTERN = "http://scmplc.begasoft.ch/plcapp/netzabdeckung/<type>?zoom=<zoom>&x=<x>&y=<y>"; private static final String CACHE_FILE = Constants.TMP_DIR + "/swisscomCoverageCache.xml.gz"; private static int requestCount = 0; public static final int DEFAULT_ZOOM = 18; public static final int RETURNED_TILE_PIXEL_SIZE = 256; public static final int FLUSH_INTERVAL = 20; private static Logger LOG = LogUtil.getLogger(); /** user-defined overrides */ public static final Map<Location,NetworkQuality> OVERRIDES = new HashMap<Location, NetworkQuality>(); static { loadCache(); } public static NetworkQuality getCoverage(double lat, double lon) { NetworkQuality override = getOverride(lat, lon); if(override != null) { return override; } int zoom = DEFAULT_ZOOM; double v = io.hummer.osm.util.Util.getVicinity(zoom); Tile t = new Tile(lon - v, lat + v, lon + v, lat - v); NetworkQuality c = cache.findInCache(t); if (c != null) { return c; } c = new NetworkQuality(); c._2g_gsm = get2gGsmCoverage(lat, lon); c._3g_umts = get3gUmtsCoverage(lat, lon); c._3g_hspa = get3gHspaCoverage(lat, lon); c._4g_lte = get4gLteCoverage(lat, lon); cache.put(t, c); requestCount++; if(requestCount % FLUSH_INTERVAL == 0) { storeCache(); } return c; } /* PRIVATE HELPER METHODS */ public static NetworkQuality getOverride(double lat, double lon) { NetworkQuality q = OVERRIDES.get(new Location(lat, lon)); //LOG.info("Network quality override (" + OVERRIDES.size() + "): " + q); return q; } public static void setOverrideIfExists(PathPoint p1) { NetworkQuality q = getOverride(p1.coordinates.lat, p1.coordinates.lon); if(q != null) { LOG.debug("Network quality override: " + q); p1.cellNetworkCoverage = q; } } private static boolean get2gGsmCoverage(double lat, double lon) { return getCoverage("gsm", DEFAULT_ZOOM, lat, lon); } private static boolean get3gUmtsCoverage(double lat, double lon) { return getCoverage("umts", DEFAULT_ZOOM, lat, lon); } private static boolean get3gHspaCoverage(double lat, double lon) { return getCoverage("hspa", DEFAULT_ZOOM, lat, lon); } private static boolean get4gLteCoverage(double lat, double lon) { return getCoverage("lte", DEFAULT_ZOOM, lat, lon); } private static boolean getCoverage(String type, int zoom, double lat, double lon) { Point p = GMapsCoordinatesConverter.convertLatLonToPixelPoint(zoom, lat, lon); try { String url = URL_PATTERN.replace("<type>", "" + type) .replace("<zoom>", "" + DEFAULT_ZOOM) .replace("<x>", "" + Math.round(p.x)) .replace("<y>", "" + Math.round(p.y)); BufferedImage img = null; img = ImageIO.read(new URL(url).openStream()); Raster r = img.getData(); double numTransparent = 0; double numNonTransparent = 0; for (int x = r.getMinX(); x - r.getMinX() < r.getWidth(); x++) { for (int y = r.getMinY(); y - r.getMinY() < r.getHeight(); y++) { int[] d = r.getPixel(x, y, (int[]) null); long opacity = d[3]; if (opacity <= 0) { numTransparent++; } else { numNonTransparent++; } } } return numNonTransparent > numTransparent; } catch (Exception e) { throw new RuntimeException(e); } } private static void storeCache() { if(!new File(Constants.TMP_DIR).exists()) { new File(Constants.TMP_DIR).mkdir(); } try { XMLUtil xmlUtil = new XMLUtil(); String str = xmlUtil.toString(cache); Util.storeStringGzipped(CACHE_FILE, str); } catch (Exception e) { throw new RuntimeException(e); } } private static void loadCache() { if(!new File(CACHE_FILE).exists()) { return; } String str = Util.loadStringFromGzip(CACHE_FILE); XMLUtil xmlUtil = new XMLUtil(); try { cache = xmlUtil.toJaxbObject(TiledMapSwisscom.class, xmlUtil.toElement(str)); } catch (Exception e) { throw new RuntimeException(e); } System.out.println("Loaded cache file: " + CACHE_FILE + " (" + cache.size() + " objects)"); } public static void main(String[] args) { System.out.println(GMapsCoordinatesConverter.convertLatLonToPixelPoint(15, 46.4772, 8.7897)); System.out.println(GMapsCoordinatesConverter.convertLatLonToPixelPoint(10, 46.101816214055304,8.69681517045248)); } }