2

WMS Webservice GeoServer WMS

I try to get Tile Information(I, J , BBOX) on selected Latitude and Longitude with zooming level in Google Map.

I used this formula to get I, J , BBOX Formula Source

private void getXYFromLatLon(double lat, double lon, final int zoom) {
    int tileSize = 256;
    // double initialResolution = 2 * Math.PI * 6378137 / tileSize;
    double initialResolution = 156543.03392804062;
    double originShift = 20037508.342789244;
    // LatLong to Meter
    double mx = lon * originShift / 180.0;
    double my = Math.log(Math.tan((90 + lat) * Math.PI / 360.0))
            / (Math.PI / 180.0);
    my = my * originShift / 180.0;
    // Meter to Pixels
    double res = initialResolution / (2 * zoom);
    double px = (mx + originShift) / res;
    double py = (my + originShift) / res;

    getBoundingBox(Double.valueOf(px).intValue(), Double.valueOf(py)
            .intValue(), zoom);
    // Pixel to tiles
    final int tx = (int) Math.ceil(px / ((tileSize)) - 1);
    final int ty = (int) Math.ceil(py / ((tileSize)) - 1);

    getTileBound(tx, ty, zoom, tileSize);

    Toast.makeText(getApplicationContext(), "X: " + tx + ",Y: " + ty,
            Toast.LENGTH_SHORT).show();

}private void getTileBound(int tx, int ty, int zoom, int tileSize) {
    double[] min = pixelToMeter(tx * tileSize, ty * tileSize, zoom);
    double[] max = pixelToMeter((tx + 1) * tileSize, (ty + 1) * tileSize,
            zoom);

    builder.append("\nMIN-X:" + min[0]).append("\nMIN-Y:" + min[1])
            .append("\nMAX-X:" + max[0]).append("\nMAX-Y:" + max[1])
            .append("\nI:" + (tx)).append("\nJ:" + (ty));
    ((TextView) findViewById(R.id.textView1)).setText(builder.toString());
    /*
     * Toast.makeText(getApplicationContext(), "X: " + min.toString() +
     * ",Y: " + max.toString(), Toast.LENGTH_SHORT).show();
     */
}public 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);
    System.out.println("xtile" + xtile);

    // Toast.makeText(getApplicationContext(),
    // xtile + "YY" + ytile + "Zoom" + (1 << zoom), Toast.LENGTH_LONG)
    // .show();
    return ("" + zoom + "/" + xtile + "/" + ytile);

}private double[] pixelToMeter(int x, int y, int zoom) {
    int tileSize = 256;
    double initialResolution = 2 * Math.PI * 6378137 / tileSize;
    double originShift = 2 * Math.PI * 6378137 / 2;
    double res = initialResolution / (2 * zoom);
    double mx = x * res - originShift;
    double my = y * res - originShift;

    return new double[] { mx, my };

}

The problem based on zooming level i'm not able to find the exact value .. Based on correct value i to have call the WMS webservices

Thanks in advance...

http://192.168.1.102:1005/geoserver/estater/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=buildings&LAYERS=kwt_buildings&INFO_FORMAT=application%2Fjson&propertyName=grid_id%2Cbuild_id&I=90&J=161&WIDTH=256&HEIGHT=256&CRS=EPSG%3A3857&STYLES=&BBOX=5342031.032794397%2C3420709.8898182083%2C5343254.02524696%2C3421932.882270771

AnanThDev
  • 337
  • 2
  • 16

1 Answers1

1

I did not look at your code, but I have mine working since years, so here it is the WMS tile provider class:

public abstract class WMSTileProvider extends UrlTileProvider {

// 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;

// array indexes for array to hold bounding boxes.
protected static final int MINX = 0;
protected static final int MAXX = 1;
protected static final int MINY = 2;
protected static final int MAXY = 3;

// cql filters
private String cqlString = "";

// Construct with tile size in pixels, normally 256, see parent class.
public WMSTileProvider(int x, int y) {
    super(x, y);
}

@SuppressWarnings("deprecation")
protected String getCql() {
    try {
        return URLEncoder.encode(cqlString, Charset.defaultCharset().name());
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return URLEncoder.encode(cqlString);
    }
}

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

// Return a web Mercator bounding box given tile x/y indexes and a zoom
// level.
protected double[] getBoundingBox(int x, int y, int zoom) {
    double tileSize = MAP_SIZE / Math.pow(2, zoom);
    double minx = TILE_ORIGIN[ORIG_X] + x * tileSize;
    double maxx = TILE_ORIGIN[ORIG_X] + (x + 1) * tileSize;
    double miny = TILE_ORIGIN[ORIG_Y] - (y + 1) * tileSize;
    double maxy = TILE_ORIGIN[ORIG_Y] - y * tileSize;

    double[] bbox = new double[4];
    bbox[MINX] = minx;
    bbox[MINY] = miny;
    bbox[MAXX] = maxx;
    bbox[MAXY] = maxy;

    return bbox;
}
}

And here is something on how i use it:

public static WMSTileProvider getWMSTileProviderByName(String layerName) {
        final String OSGEO_WMS = "http://yourserver/geoserver/gwc/service/wms/?"
                + "LAYERS=" + layerName
                + "&FORMAT=image/png8&"
                + "PROJECTION=EPSG:3857&"
                + "TILEORIGIN=lon=-20037508.34,lat=-20037508.34&"
                + "TILESIZE=w=256,h=256"
                + "&MAXEXTENT=-20037508.34,-20037508.34,20037508.34,20037508.34&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&SRS=EPSG:3857"
                + "&BBOX=%f,%f,%f,%f&WIDTH=256&HEIGHT=256";

        return new WMSTileProvider(256, 256) {

            @Override
            public synchronized URL getTileUrl(int x, int y, int zoom) {
                final double[] bbox = getBoundingBox(x, y, zoom);
                String s = String.format(Locale.US, OSGEO_WMS, bbox[MINX], bbox[MINY], bbox[MAXX], bbox[MAXY]);
                try {
                    return new URL(s);
                } catch (MalformedURLException e) {
                    throw new AssertionError(e);
                }
            }
        };
    }

Can't give you more code, but I hope can help you

EDIT: Given the comment, now i see what you need. Here it is some code (old but working) on which you have to work a bit, it was a sort of hack:

    private static final double[] TILES_ORIGIN = {-20037508.34789244, 20037508.34789244};//TODO Duplicate from WMS PROVIDER, put as utils
    // Size of square world map in meters, using WebMerc projection.
    private static final double MAP_SIZE = 20037508.34789244 * 2;//TODO Duplicate from WMS PROVIDER, put as utils
    private static final double ORIGIN_SHIFT = Math.PI * 6378137d;

/**
     * Transform the y map meter in y cordinate
     *
     * @param latitude the latitude of map
     * @return meters of y cordinate
     */
    private double inMetersYCoordinate(double latitude) {
        if (latitude < 0) {
            return -inMetersYCoordinate(-latitude);
        }
        return (Math.log(Math.tan((90d + latitude) * Math.PI / 360d)) / (Math.PI / 180d)) * ORIGIN_SHIFT / 180d;
    }

    /**
     * Transform the x map meter in x cordinate
     *
     * @param longitude the longitude of map
     * @return meters of x cordinate
     */
    private double inMetersXCoordinate(double longitude) {
        return longitude * ORIGIN_SHIFT / 180.0;
    }

/**
     * Get the Tile from x and y cordinates
     *
     * @param pointX    x of the map
     * @param pointY    y of the map
     * @param zoomLevel zoom of Tile
     * @return the relative TileDataInfo
     */
private TileDataInfo getTileByCoordinate(double pointX, double pointY, int zoomLevel) {
    final double tileDim = MAP_SIZE / Math.pow(2d, zoomLevel);

    final int tileX = (int) ((pointX - TILES_ORIGIN[0]) / tileDim);
    final int tileY = (int) ((TILES_ORIGIN[1] - pointY) / tileDim);

    return new TileDataInfo(tileX, tileY, zoomLevel);
}

private static class TileDataInfo {
    int tileX;
    int tileY;
    int tileZoom;

    public TileDataInfo(int tileX, int tileY, int tileZoom) {
        this.tileX = tileX;
        this.tileY = tileY;
        this.tileZoom = tileZoom;
    }

}

In order to get the code right, you have to convert latitude in meters using the "inMetersYCoordinate", the longitude using "inMetersXCoordinate" and then use "getTileByCoordinate" to calculate the tile x,y,z (i,j,zoom for you)

N Dorigatti
  • 3,482
  • 2
  • 22
  • 33
  • edited the answer and added the code. You can use those functions to get the x,y and z (which is the zoom level) of the clicked tile given clicked point and actual zoom level. – N Dorigatti Sep 04 '15 at 07:52
  • Thanks Dorigatti for quick response.. Yeah same code used for Tile overlay.. But i need to get the Tile information I and J value when i click the map .. onMapClick(LatLng arg0) .. Based on Lat Long and zoomlevel(mMap.getCameraPosition().zoom) –When OnMapClick method fire.. I call the getXYFromLatLon(double lat, double lon, final int zoom) – AnanThDev Sep 04 '15 at 07:53
  • Thanks.. But when i used the editing code. TileInfo info = new TileInfo(); TileDataInfo infos = info.getTileByCoordinate( info.inMetersXCoordinate(arg0.longitude), info.inMetersYCoordinate(arg0.latitude), (int) mMap.getCameraPosition().zoom); Lat : 29.37212204495948 and Long: 48.00505343824625.. and Zoom level: 14 Ouput: Tile x:10376, TileY:6792,.. But I and J should be less than 256..How to calculate that – AnanThDev Sep 04 '15 at 08:10
  • why less than 256? can you please clarify what you want to get? the tiles coordinates or the pixel inside the tile (which is i think way more difficult to get). You say you want I and J values, but what are them for you? – N Dorigatti Sep 04 '15 at 08:29
  • here is Link got from demo website If i click the map .. Link will generate based on selected location.. http://192.168.1.102:1005/geoserver/estater/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetFeatureInfo&FORMAT=image%2Fpng&TRANSPARENT=true&QUERY_LAYERS=buildings&LAYERS=buildings&INFO_FORMAT=application%2Fjson&propertyName=grid_id%2Cbuild_id&I=119&J=103&WIDTH=256&HEIGHT=256&CRS=EPSG%3A3857&STYLES=&BBOX=5342031.032794397%2C3421932.88227077%2C5343254.02524696%2C3423155.874723333 Same as i Have to get in Android APP... http://docs.geoserver.org/2.7.1/user/services/wms/reference.html#getfeatureinfo – AnanThDev Sep 04 '15 at 09:03
  • then it is way different what you need to get. You need to obtain lower left and upper right (or lowright and upleft, thats not important) coordinates of the clicked tile and then go by propoprtion (clicked point is x% and y% of the tile, so its x% and y% of 256 (assuming you are showing tiles of 256)). there should be some code to get tiles bound given coordinates, but I don't remember where I have it... if I can find, I'll put another answer, ok? – N Dorigatti Sep 04 '15 at 09:42
  • Thanks Dorigatti for helping me.. Yeah Sure.. if you have another code.. you can post it,,, once again thanks – AnanThDev Sep 04 '15 at 09:55