How to load geoserver WMS layer on osmdroid map in particular bounding box?

1k Views Asked by At

I am using osmdroid library to show mapview in my application. I have to load wms layer in my osm map to show village boundaries.

I have search on google and stack overflow and I found following blogs and posts

  1. How to work OSMDroid with Web Map Service (WMS) used by the private provider?
  2. android mapview with custom wms tile provider
  3. Using getTileURL in Android Application with GeoServer
  4. https://osmdroid.github.io/osmdroid/Map-Sources.html
  5. https://docs.geoserver.org/latest/en/user/services/wms/reference.html#getmap

I referred these and tried to implement same and I am able to load wms layer on osm map successfully. But it is loaded in multiple loop you can see in below image

enter image description here

I want this wms layer only be loaded in mentioned bounding box which I am passing in wms Api url.

My code to calling wms layer api

public class TileProviderFactory {
private static final String TAG = "TileProviderFactory";

private String version = "1.1.0";
private String url = "http://49.206.244.230:8080/geoserver/cfr/wms";
private String layers = "cfr:bastar_villages";

public WMSTileProvider getWmsTileProvider() {

    String[] baseUrl = {url};
    
    final String WMS_FORMAT_STRING =
            url +
                    "?service=WMS" +
                    "&version=" + version +
                    "&request=GetMap" +
                    "&layers=" + layers +
                    "&bbox=81.3445510864258,18.6015472412109,82.2461547851562,19.5618953704834" +
                    "&width=721" +
                    "&height=768" +
                    "&srs=EPSG:4326" +  // NB This is important, other SRS's won't work.
                    "&format=image/png" +
                    "&transparent=true";


    WMSTileProvider tileProvider = new WMSTileProvider(baseUrl, 256) {
        @Override
        public String getTileURLString(long pMapTileIndex) {
            WebMercatorBoundingBox bb = new WebMercatorBoundingBox(MapTileIndex.getX(pMapTileIndex), MapTileIndex.getY(pMapTileIndex), MapTileIndex.getZoom(pMapTileIndex));
            String s = String.format(
                    Locale.ENGLISH,
                    WMS_FORMAT_STRING,
                    bb.getWest(),
                    bb.getSouth(),
                    bb.getEast(),
                    bb.getNorth());
            Log.d(TAG,"Fetching map tile: " + s);
            return s;
        }
    };
    return tileProvider;
}}

WebMercatorBoundingBox class

public class WebMercatorBoundingBox {
double north;
double south;
double east;
double west;


// Web Mercator n/w corner of the map.
private static final double[] TILE_ORIGIN = {-20037508.34789244,    20037508.34789244};
//array indexes for that data
private static final int ORIG_X = 0;
private static final int ORIG_Y = 1; // "

// Size of square world map in meters, using WebMerc projection.
private static final double MAP_SIZE = 20037508.34789244 * 2;

protected WebMercatorBoundingBox(final int x, final int y, final int zoom) {
    north = tile2lat(y, zoom);
    south = tile2lat(y + 1, zoom);
    west = tile2lon(x, zoom);
    east = tile2lon(x + 1, zoom);
}
double tile2lon(int x, int z) {
    double tileSize = MAP_SIZE / Math.pow(2.0, z);
    return  TILE_ORIGIN[ORIG_X] + x * tileSize;
}

double tile2lat(int y, int z) {
    double tileSize = MAP_SIZE / Math.pow(2.0, z);
    return TILE_ORIGIN[ORIG_Y] - y * tileSize;
}

public double getNorth(){
    return this.north;
}
public double getSouth(){
    return this.south;
}
public double getEast(){
    return this.east;
}
public double getWest(){
    return this.west;
}}

WMSTileProvider abstract class

public abstract class WMSTileProvider extends OnlineTileSourceBase {

// cql filters
private String cqlString = "";

// Construct with tile size in pixels, normally 256, see parent class.
public WMSTileProvider(String[] baseurl, int tileSizeInPixels) {
    super("WMS tile source", 1 ,19,tileSizeInPixels,"png",baseurl);

}

protected String getCql() {
    return URLEncoder.encode(cqlString);
}

public void setCql(String c) {
    cqlString = c;
}
}

WebMercatorBoundingBox return following bounding box(value of s):

D/TileProviderFactory: Fetching map tile: http://49.206.244.230:8080/geoserver/cfr/wms?service=WMS&version=1.1.0&request=GetMap&layers=cfr:bastar_villages&bbox=-626172.135872,-1878516.407615,0.000000,-1252344.271743&width=721&height=768&srs=EPSG:4326&format=image/png&transparent=true
D/TileProviderFactory: Fetching map tile: http://49.206.244.230:8080/geoserver/cfr/wms?service=WMS&version=1.1.0&request=GetMap&layers=cfr:bastar_villages&bbox=-626172.135872,626172.135872,0.000000,1252344.271743&width=721&height=768&srs=EPSG:4326&format=image/png&transparent=true
D/TileProviderFactory: Fetching map tile: http://49.206.244.230:8080/geoserver/cfr/wms?service=WMS&version=1.1.0&request=GetMap&layers=cfr:bastar_villages&bbox=-1252344.271743,0.000000,-626172.135872,626172.135872&width=721&height=768&srs=EPSG:4326&format=image/png&transparent=true

Please help me to figure out my mistake or give me any suggestions how I achieve my goal.

1

There are 1 best solutions below

7
Ian Turton On

You seem to be using the whole maps bounding box to make your tile requests - as you can see with http://49.206.244.230:8080/geoserver/cfr/wms?service=WMS&version=1.1.0&request=GetMap&layers=cfr:bastar_villages&bbox=81.3445510864258,18.6015472412109,82.2461547851562,19.5618953704834&width=721&height=768&srs=EPSG:4326&format=image/png&transparent=true

enter image description here

But you are asking for it in each tile, so you need to calculate the bounds for each tile (which changes the size to 256x256 as well). At this point you should probably be working in WebMercator coordinates (EPSG:3857) (otherwise the curvature of the Earth makes the maths hard).

This is what I think WebMercatorBoundingBox should give you so combining those coordinates (they will be in the thousands to millions range) with an SRS of EPSG:3857 should return you the required tiles. Once you are using those bounds you will need to make sure that you have correctly set the tile size to 265x256 in the width and height parameters and that the SRS is correctly set too.

Update

From a look at the server you could get use the WGS tile set and start your calculations from:

<TileMatrixSet>
  <ows:Identifier>EPSG:4326</ows:Identifier>
  <ows:SupportedCRS>urn:ogc:def:crs:EPSG::4326</ows:SupportedCRS>
  <TileMatrix>
    <ows:Identifier>EPSG:4326:0</ows:Identifier>
    <ScaleDenominator>2.795411320143589E8</ScaleDenominator>
    <TopLeftCorner>90.0 -180.0</TopLeftCorner>
    <TileWidth>256</TileWidth>
    <TileHeight>256</TileHeight>
    <MatrixWidth>2</MatrixWidth>
    <MatrixHeight>1</MatrixHeight>
  </TileMatrix>

and then you would get lat/lon out and could use EPSG:4326.