Android change google map tile with custom tiles - android

Is it possible to change google map API v3 standart map to my own custom map coming from url? I know that OSMdroid provide it but i want work with google map API. Is it possible?

it is indeed possible by using WMS services (if you don't know what they are, please google it).
Here is some code you can use:
The WMSTile provider is used by GoogleMapsAPI to set the map provider:
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 you can instantiate a custom one from your URL in such a way:
public static WMSTileProvider getWMSTileProviderByName(String layerName) {
final String OSGEO_WMS = "http://YOURWMSSERVERURL?"
+ "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);
}
}
};
}
Add to your map:
TileProvider tileProvider = getWMSTileProviderByName("MYLAYERNAME");
TileOverlay tileOverlay = myMap.addTileOverlay(new TileOverlayOptions()
.tileProvider(tileProvider));
You should also set the map type to MAP_NONE when using a custom tile provider (if it is not transparent), so you avoid to load gmaps tiles that are hidden behind your custom map.

Related

android mapview with custom wms tile provider

i want to load my wms server to show tiles from there. i used carto/nutiteq and everything is ok but i want it open source or free license . then i try osmdroid library but i can't implement my wms can anyone help me ?
// 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; //
private static String mLayername = "";
// 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;
private String layer = "";
/**
* Constructor
*
* #param aName a human-friendly name for this tile source
* #param aBaseUrl the base url(s) of the tile server used when constructing the url to download the tiles http://sedac.ciesin.columbia.edu/geoserver/wms
*/
public WMSTileProvider(String aName, String[] aBaseUrl, String layername) {
super(aName, 8, 22, 255, "image/png", aBaseUrl);
mLayername = layername;
}
final String WMS_FORMAT_STRING =
"http://dev.shiveh.com/shiveh?service=WMS&request=GetMap&layers=Shiveh%3AShivehGSLD256&styles=&format=image%2Fpng&transparent=false&version=1.1.1&height=256&width=256&srs=EPSG%3A4326&bbox=";
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;
}
The coordinate reference system in your url EPSG:4326 which is lat/lon wgs84. However the equations you have appear to look like the equations to convert from slippy map coordinates to EPSG:900913.
Does your server support that CRS? Try switching the CRS url parameter to EPSG:900913 or change the equation to compute the coordinates for the requested tile

Google Map Tile Provider (GeoServer And WMS)

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
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)

Calculate the area of a polygon drawn on google maps in an Android application

I would like to calculate the are of a polygon drawn in a map fragment for a college project.
This is how I draw my polygon.
#Override
public void onMapClick(LatLng point) {
//tvLocInfo.setText("New marker added#" + point.toString());
map.addMarker(new MarkerOptions().position(point).draggable(true).title(point.toString()));
markerClicked = false;
}
#Override
public void onMapLongClick(LatLng point) {
//tvLocInfo.setText("New marker added#" + point.toString());
map.clear();
}
#Override
public boolean onMarkerClick(Marker marker) {
if(markerClicked){
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions.add(marker.getPosition());
polygonOptions.strokeColor(Color.RED);
polygonOptions.fillColor(Color.BLUE);
polygon = map.addPolygon(polygonOptions);
//Area = google.maps.geometry.spherical.computeArea(polygon.getPath().getArray());
}else{
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions = new PolygonOptions().add(marker.getPosition());
markerClicked = true;
}
I have seen this code on how to calculate the area but I am unsure how to implement it in my application and calculate the area of my polygon.
I use this code to calculate an area of a GPS with Android:
private static final double EARTH_RADIUS = 6371000;// meters
public static double calculateAreaOfGPSPolygonOnEarthInSquareMeters(final List<Location> locations) {
return calculateAreaOfGPSPolygonOnSphereInSquareMeters(locations, EARTH_RADIUS);
}
private static double calculateAreaOfGPSPolygonOnSphereInSquareMeters(final List<Location> locations, final double radius) {
if (locations.size() < 3) {
return 0;
}
final double diameter = radius * 2;
final double circumference = diameter * Math.PI;
final List<Double> listY = new ArrayList<Double>();
final List<Double> listX = new ArrayList<Double>();
final List<Double> listArea = new ArrayList<Double>();
// calculate segment x and y in degrees for each point
final double latitudeRef = locations.get(0).getLatitude();
final double longitudeRef = locations.get(0).getLongitude();
for (int i = 1; i < locations.size(); i++) {
final double latitude = locations.get(i).getLatitude();
final double longitude = locations.get(i).getLongitude();
listY.add(calculateYSegment(latitudeRef, latitude, circumference));
Log.d(LOG_TAG, String.format("Y %s: %s", listY.size() - 1, listY.get(listY.size() - 1)));
listX.add(calculateXSegment(longitudeRef, longitude, latitude, circumference));
Log.d(LOG_TAG, String.format("X %s: %s", listX.size() - 1, listX.get(listX.size() - 1)));
}
// calculate areas for each triangle segment
for (int i = 1; i < listX.size(); i++) {
final double x1 = listX.get(i - 1);
final double y1 = listY.get(i - 1);
final double x2 = listX.get(i);
final double y2 = listY.get(i);
listArea.add(calculateAreaInSquareMeters(x1, x2, y1, y2));
Log.d(LOG_TAG, String.format("area %s: %s", listArea.size() - 1, listArea.get(listArea.size() - 1)));
}
// sum areas of all triangle segments
double areasSum = 0;
for (final Double area : listArea) {
areasSum = areasSum + area;
}
// get abolute value of area, it can't be negative
return Math.abs(areasSum);// Math.sqrt(areasSum * areasSum);
}
private static Double calculateAreaInSquareMeters(final double x1, final double x2, final double y1, final double y2) {
return (y1 * x2 - x1 * y2) / 2;
}
private static double calculateYSegment(final double latitudeRef, final double latitude, final double circumference) {
return (latitude - latitudeRef) * circumference / 360.0;
}
private static double calculateXSegment(final double longitudeRef, final double longitude, final double latitude,
final double circumference) {
return (longitude - longitudeRef) * circumference * Math.cos(Math.toRadians(latitude)) / 360.0;
}
I could also use the following polygon which is static if calculating the area of the drawn polygon is not possible.
Polygon UCCpolygon = map.addPolygon(new PolygonOptions()
.add(new LatLng(51.893728, -8.491865),
new LatLng(51.893550, -8.492479),
new LatLng(51.893216, -8.492224),
new LatLng(51.893404, -8.491598))
.strokeColor(Color.RED)
.fillColor(Color.BLUE));
Thanks for the help!
Sean
There's already a library for that.
import com.google.maps.android.SphericalUtil;
//...
List<LatLng> latLngs = new ArrayList<>();
latLngs.add(new LatLng(51.893728, -8.491865));
latLngs.add(new LatLng(51.893550, -8.492479));
latLngs.add(new LatLng(51.893216, -8.492224));
latLngs.add(new LatLng(51.893404, -8.491598));
Log.i(TAG, "computeArea " + SphericalUtil.computeArea(latLngs));
For me the output is computeArea 1920.8879882782069
If you want to use SphericalUtils code without any library, you can use following code. it's taken from opensource code from SphericalUtils.java and other class. I have taken this code and used it as i was using MapBox and MapBox does not have implemented the calculateArea function in Turf.
import java.util.List;
import pojo.LatLng;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.tan;
import static java.lang.Math.toRadians;
public class PolygonUtils {
/**
* The earth's radius, in meters.
* Mean radius as defined by IUGG.
*/
static final double EARTH_RADIUS = 6371009;
/**
* Returns the area of a closed path on Earth.
* #param path A closed path.
* #return The path's area in square meters.
*/
public static double computeArea(List<LatLng> path) {
return abs(computeSignedArea(path,EARTH_RADIUS));
}
/**
* Returns the signed area of a closed path on a sphere of given radius.
* The computed area uses the same units as the radius squared.
* Used by SphericalUtilTest.
*/
static double computeSignedArea(List<LatLng> path, double radius) {
int size = path.size();
if (size < 3) { return 0; }
double total = 0;
LatLng prev = path.get(size - 1);
double prevTanLat = tan((PI / 2 - toRadians(prev.getLatitude())) / 2);
double prevLng = toRadians(prev.getLongitude());
// For each edge, accumulate the signed area of the triangle formed by the North Pole
// and that edge ("polar triangle").
for (LatLng point : path) {
double tanLat = tan((PI / 2 - toRadians(point.getLatitude())) / 2);
double lng = toRadians(point.getLongitude());
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return total * (radius * radius);
}
/**
* Returns the signed area of a triangle which has North Pole as a vertex.
* Formula derived from "Area of a spherical triangle given two edges and the included angle"
* as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2.
* See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71
* The arguments named "tan" are tan((pi/2 - latitude)/2).
*/
private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) {
double deltaLng = lng1 - lng2;
double t = tan1 * tan2;
return 2 * atan2(t * sin(deltaLng), 1 + t * cos(deltaLng));
}
}

WMS On Android tile loading issue

I'm using Google Maps v2 to display tiles from a wms. I referred this
site. Problem in loading tiles, they are loading multiple times i dont konw y? Can any1 help me.
Here is my code
package com.example.testgooglemaps;
import android.app.Activity;
import android.os.Bundle;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.TileOverlayOptions;
import com.google.android.gms.maps.model.TileProvider;
public class Lanch extends Activity {
// Google Map
private GoogleMap googleMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lanch);
try {
// Loading map
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* function to load map. If map is not created it will create it for you
* */
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
// check if map is created successfully or not
if (googleMap != null) {
setUpMap();
}
}
}
#Override
protected void onResume() {
super.onResume();
initilizeMap();
}
private void setUpMap() {
TileProvider wmsTileProvider = TileProviderFactory.getOsgeoWmsTileProvider();
googleMap.addTileOverlay(new TileOverlayOptions().tileProvider(wmsTileProvider));
// to satellite so we can see the WMS overlay.
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
}
}
TileProvider class...
package com.example.testgooglemaps;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
import android.util.Log;
public class TileProviderFactory {
public static WMSTileProvider getOsgeoWmsTileProvider() {
final String OSGEO_WMS = "http://localhost/geoserver/magnamaps/wms?service=WMS&version=1.1.0&request=GetMap&layers=magnamaps:bang_apartments&styles=&bbox=%f,%f,%f,%f&width=256&height=256&crs=EPSG:4326&format=image/png&transparent=true";
WMSTileProvider tileProvider = new WMSTileProvider(256, 256) {
#Override
public synchronized URL getTileUrl(int x, int y, int zoom) {
double[] bbox = getBoundingBox(x, y, zoom);
String s = String.format(Locale.US, OSGEO_WMS, bbox[MINX], bbox[MINY], bbox[MAXX], bbox[MAXY]);
Log.d("WMSDEMO", s);
URL url = null;
try {
url = new URL(s);
} catch (MalformedURLException e) {
throw new AssertionError(e);
}
return url;
}
};
return tileProvider;
}
}
WMSTileProvider class...
package com.example.testgooglemaps;
import java.net.URLEncoder;
import com.google.android.gms.maps.model.UrlTileProvider;
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);
}
protected String getCql() {
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;
}
}
EDIT : While initializing map itself, zoom level is set to 3, Inside this method getTileUrl(int x, int y, int zoom)
In WMSTileProvider.getBoundingBox you are computing the bounding box in units of the Web Mercator projection, which are meters. In your OSGEO_WMS URL string, you are specifying that the bbox units are in EPSG:4326 (degrees). It's likely that the query for each tile is incorrect as a result.
See the WMS reference for bbox and srs:
bbox: Bounding box for map extent. Value is minx,miny,maxx,maxy in
units of the SRS.
Try replacing your srs value with EPSG:3857 (WebMercator)

Using getTileURL in Android Application with GeoServer

We are just starting to work with Google Maps on Android and have a GeoServer set up to provide tiles which we would like to add as overlay on the map. So far, I have followed a few tutorials and references to get started.
For getting MyLocation
Setting up WMS on Android
WMS Reference
The problem: While the url that I am generating in the getTileUrl function in the TileProviderFactory does indeed return a png image when I set a breakpoint and copy and paste the url into a browser, it does not load onto the map as an overlay on the Android device. There are no errors being thrown from what I can see and after reading this I am not sure if there will be any as they have indicated that the errors are being muted.
What I am wondering is if you can see any immediate issues in my code or have any suggestions for debugging where I will be able to tell if the application is actually communicating with my GeoServer to retrieve the image or not. I've looked at the log on the GeoServer and it seems as though only my browser requests are going through and it's not receiving any requests from Android (it's a bit difficult to tell because we have other applications using the server as well). The Android phone is connected by both wifi and cell and has gps enabled. As a last resort I have tried changing the tile overlay zIndex and setting it to visible but this didn't seem to make any difference.
EDIT: Android device is definitely NOT communicating with GeoServer at this point.
EDIT 2: Able to load static images from websites
(like this) as overlays and found that I am getting the following exception on testing out an HTTP Request to the formed URL:
W/System.err(10601): java.net.SocketException: The operation timed out
W/System.err(10601): at org.apache.harmony.luni.platform.OSNetworkSystem
.connectStreamWithTimeoutSocketImpl(Native Method)
W/System.err(10601): at org.apache.harmony.luni.net.PlainSocketImpl
.connect(PlainSocketImpl.java:244)
W/System.err(10601): at org.apache.harmony.luni.net.PlainSocketImpl
.connect(PlainSocketImpl.java:533)
W/System.err(10601): at java.net.Socket
.connect(Socket.java:1074)
W/System.err(10601): at org.apache.http.conn.scheme.PlainSocketFactory
.connectSocket(PlainSocketFactory.java:119)
Thanks.
MapTestActivity
public class MapTestActivity extends FragmentActivity
implements LocationListener, LocationSource{
private GoogleMap mMap;
private OnLocationChangedListener mListener;
private LocationManager locationManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_test);
setupLocationManager();
setupMapIfNeeded();
}
private void setupLocationManager() {
this.locationManager =
(LocationManager) getSystemService(LOCATION_SERVICE);
if (locationManager != null) {
boolean gpsIsEnabled = locationManager.isProviderEnabled(
LocationManager.GPS_PROVIDER);
boolean networkIsEnabled = locationManager.isProviderEnabled(
LocationManager.NETWORK_PROVIDER);
if(gpsIsEnabled) {
this.locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000L, 10F, this);
}
else if(networkIsEnabled) {
this.locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 5000L, 10F, this);
}
else {
//Show an error dialog that GPS is disabled...
}
}
else {
// Show some generic error dialog because
// something must have gone wrong with location manager.
}
}
private void setupMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
mMap.setLocationSource(this);
}
}
private void setUpMap() {
// TODO Auto-generated method stub
mMap.setMyLocationEnabled(true);
TileProvider geoServerTileProvider = TileProviderFactory
.getGeoServerTileProvider();
TileOverlay geoServerTileOverlay = mMap.addTileOverlay(
new TileOverlayOptions()
.tileProvider(geoServerTileProvider)
.zIndex(10000)
.visible(true));
}
// Non-relevant listener methods removed
}
TileProviderFactory
public class TileProviderFactory {
public static GeoServerTileProvider getGeoServerTileProvider() {
String baseURL = "mytileserver.com";
String version = "1.3.0";
String request = "GetMap";
String format = "image/png";
String srs = "EPSG:900913";
String service = "WMS";
String width = "256";
String height = "256";
String styles = "";
String layers = "wtx:road_hazards";
final String URL_STRING = baseURL +
"&LAYERS=" + layers +
"&VERSION=" + version +
"&SERVICE=" + service +
"&REQUEST=" + request +
"&TRANSPARENT=TRUE&STYLES=" + styles +
"&FORMAT=" + format +
"&SRS=" + srs +
"&BBOX=%f,%f,%f,%f" +
"&WIDTH=" + width +
"&HEIGHT=" + height;
GeoServerTileProvider tileProvider =
new GeoServerTileProvider(256,256) {
#Override
public synchronized URL getTileUrl(int x, int y, int zoom) {
try {
double[] bbox = getBoundingBox(x, y, zoom);
String s = String.format(Locale.US, URL_STRING, bbox[MINX],
bbox[MINY], bbox[MAXX], bbox[MAXY]);
Log.d("GeoServerTileURL", s);
URL url = null;
try {
url = new URL(s);
}
catch (MalformedURLException e) {
throw new AssertionError(e);
}
return url;
}
catch (RuntimeException e) {
Log.d("GeoServerTileException",
"getTile x=" + x + ", y=" + y +
", zoomLevel=" + zoom +
" raised an exception", e);
throw e;
}
}
};
return tileProvider;
}
}
GeoServerTileProvider
public abstract class GeoServerTileProvider 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 MINY = 1;
protected static final int MAXX = 2;
protected static final int MAXY = 3;
public GeoServerTileProvider(int width, int height) {
super(width, height);
}
// 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;
}
}
This turned out to be a network issue and completely unrelated to my implementation which is "correct". I guess this question will serve well as an example for others who are getting started with Android + GeoServer implementation so I will leave it up.

Categories

Resources