package com.nutiteq.advancedmap3.datasource; import android.net.Uri; import com.nutiteq.core.MapBounds; import com.nutiteq.core.MapPos; import com.nutiteq.core.MapTile; import com.nutiteq.datasources.HTTPTileDataSource; import com.nutiteq.projections.Projection; /** * A custom tile source makes WMS request. Supports only WGS84 (EPSG:4326) requests * */ public class HttpWmsTileDataSource extends HTTPTileDataSource { private String baseUrl; private String layer; private String format; private String style; private boolean wgsWms; private Projection projection; private int tileSize = 256; /** * Creates WMS DataSource, based on tiles. Map service must support EPSG:3857 or EPSG:4326. * - EPSG:3857 has full compatibility and accuracy, * - many services with EPSG:4326 work also, but on low zooms (world view) it is inaccurate, * because map display projection is always EPSG:3857 (in SDK 3.0) * * Only GetMap is implemented * * @param minZoom minimal zoom * @param maxZoom max zoom for map server * @param proj datasource projection, currently should be EPSG:3857 * @param wgsWms false - uses EPSG:3857 for server, true - uses WGS84 (EPSG:4326) which is less accurate in low zooms * @param baseUrl You need to configure direct map URL, GetCapabilities is NOT used here * @param style - usually empty string, comma separated * @param layer comma-separated list of layers * @param format e.g. image/png, image/jpeg */ public HttpWmsTileDataSource(int minZoom, int maxZoom, Projection proj, boolean wgsWms, String baseUrl, String style, String layer, String format) { super(minZoom, maxZoom, baseUrl); this.baseUrl = baseUrl; this.style = style; this.layer = layer; this.format = format; this.wgsWms = wgsWms; this.projection = proj; } @Override protected String buildTileUrl(MapTile tile) { String srs = "EPSG:3857"; String bbox = getTileBbox(tile); if(wgsWms){ srs = "EPSG:4326"; } Uri.Builder uri = createBaseUri("GetMap", srs); uri.appendQueryParameter("BBOX", bbox); return uri.build().toString(); } private Uri.Builder createBaseUri(String request, String srs) { Uri.Builder uri = Uri.parse(baseUrl).buildUpon(); uri.appendQueryParameter("LAYERS", layer); uri.appendQueryParameter("FORMAT", format); uri.appendQueryParameter("SERVICE", "WMS"); uri.appendQueryParameter("VERSION", "1.1.0"); uri.appendQueryParameter("REQUEST", request); uri.appendQueryParameter("STYLES", style); uri.appendQueryParameter("EXCEPTIONS", "application/vnd.ogc.se_inimage"); uri.appendQueryParameter("SRS", srs); uri.appendQueryParameter("WIDTH", Integer.toString(tileSize)); uri.appendQueryParameter("HEIGHT", Integer.toString(tileSize)); return uri; } private String getTileBbox(MapTile tile) { MapBounds envelope = tileBounds(tile.getX(), tile.getY(), tile.getZoom(), projection); // Convert corners to WGS84 if maps server needs it. if(wgsWms){ envelope = new MapBounds(projection.toWgs84(envelope.getMin()),projection.toWgs84(envelope.getMax())); } String bbox = "" + envelope.getMin().getX() + "," + envelope.getMin().getY() + "," + envelope.getMax().getX() + "," + envelope.getMax().getY(); return bbox; } public MapBounds tileBounds(int tx, int ty, int zoom, Projection proj) { MapBounds bounds = proj.getBounds(); double boundWidth = bounds.getMax().getX() - bounds.getMin().getX(); double boundHeight = bounds.getMax().getY() - bounds.getMin().getY(); int xCount = Math.max(1, (int) Math.round(boundWidth / boundHeight)); int yCount = Math.max(1, (int) Math.round(boundHeight / boundWidth)); double resx = boundWidth / xCount / (tileSize * (double) (1<<(zoom))); double resy = boundHeight / yCount / (tileSize * (double) (1<<(zoom))); double minx = ((double) tx + 0) * tileSize * resx + bounds.getMin().getX(); double maxx = ((double) tx + 1) * tileSize * resx + bounds.getMin().getX(); double miny = -((double) ty + 1) * tileSize * resy + bounds.getMax().getY(); double maxy = -((double) ty + 0) * tileSize * resy + bounds.getMax().getY(); MapBounds env = new MapBounds(new MapPos(minx,miny), new MapPos(maxx,maxy)); return env; } }