/
WmsMapActivity.java
153 lines (120 loc) · 6.31 KB
/
WmsMapActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package com.carto.advancedmap.sections.overlaydatasources;
import android.net.Uri;
import android.os.Bundle;
import com.carto.advancedmap.baseclasses.activities.MapBaseActivity;
import com.carto.core.MapBounds;
import com.carto.core.MapPos;
import com.carto.core.MapTile;
import com.carto.datasources.HTTPTileDataSource;
import com.carto.layers.RasterTileLayer;
import com.carto.projections.Projection;
public class WmsMapActivity extends MapBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// MapBaseActivity creates and configures mapView
super.onCreate(savedInstanceState);
// USGS Base map: http://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer
String url = "http://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WmsServer?";
String layers = "0";
HttpWmsTileDataSource wms = new HttpWmsTileDataSource(0, 14, contentView.projection, false, url, "", layers, "image/png8");
RasterTileLayer wmsLayer = new RasterTileLayer(wms);
// Calculate zoom bias, basically this is needed to 'undo' automatic DPI scaling, we will display original raster with close to 1:1 pixel density
double zoomLevelBias = Math.log(contentView.mapView.getOptions().getDPI() / 160) / Math.log(2);
wmsLayer.setZoomLevelBias((float) zoomLevelBias);
contentView.mapView.getLayers().add(wmsLayer);
// finally animate map to map coverage
MapPos position = contentView.projection.fromWgs84(new MapPos(-100, 40));
contentView.mapView.setFocusPos(position, 1);
contentView.mapView.setZoom(5, 1);
}
/**
* A custom tile source makes WMS request. Supports only WGS84 (EPSG:4326) requests
*/
private static 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
*/
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(String baseUrl, 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;
}
}
}