Saturday, 1 November 2008

Selecting WMS Layers

WMS (Web Map Services) provide a standard means of downloading maps from the internet and a MapActivity allows to layer maps obtained this way onto the Google baselayer. The mechanism of this was a bit explained in a previous post, but here I want to talk a bit about managing a number of user selectable WMS Layers.

  1. First of all WMS servers provide all the information about their maps in a capabilities document, an XML description of maps and their properties provided by that server. Every user-downloadable map comes as a Layer element in that document. So if we give users the ability to put in the base url of an WMS server, parsing the document for available layers is not so hard and can be done with an XmlPullParser. The base URL for such an WMS Layer is the URL in the picture, for the ICEDS server hosted at University College London. This is the complete URL for the capabilities document from that server: http://iceds.ge.ucl.ac.uk/cgi-bin/icedswms?service=wms&version=1.1.0&request=GetCapabilities.
  2. I have quite a simple pull parser that will not trap all errors and such, but is good enough for a start to extract all the layers. These are then displayed in a ListActivity, which has a ListAdapter to display the layer titles:

    public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.wmslayerselector);

    Button b1 = (Button) findViewById(R.id.button);
    b1.setOnClickListener(new View.OnClickListener() {
    public void onClick(View arg0) {
    finish();
    }
    });

    Intent intent = getIntent();
    String wmsUrl = intent.getExtras().getString("wmsurl");
    WMSService wmsservice = new WMSService(wmsUrl);
    layers = wmsservice.getLayers();

    ListAdapter adapter = new ArrayAdapter(
    this, // Context.
    android.R.layout.simple_list_item_1,
    layers); // Pass in the cursor to bind to.

    // Bind to our new adapter.
    setListAdapter(adapter);
    }


  3. My onListItemClick() then inserts the selected layer into a ContentProvider for future use:

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
    WMSLayer layer = layers.get(position);
    Log.e(TAG, layer.toString());
    ContentValues values = new ContentValues();
    values.put(WMSLayerContentProvider.WMSLayerData.TITLE, layer.getTitle());
    values.put(WMSLayerContentProvider.WMSLayerData.NAME, layer.getName());
    values.put(WMSLayerContentProvider.WMSLayerData.BASEURL, layer.getBaseUrl());

    getContentResolver().insert(WMSLayerContentProvider.WMSLayerData.CONTENT_URI, values);}

    (There is a little issue with that WMS Server: technically, all layers with a NAME should be displayable, but this servers has some layers with names that are just used for grouping and will just display an error message when requested).

    Whenever I display a map, it now checks for those added WMS Layers:

    protected void loadWMSLayers(){
    List overlays = view.getOverlays();
    overlays.clear();

    Cursor wmsservers = null;
    try {
    String selection = WMSLayerContentProvider.WMSLayerData.VISIBLE + " = 1";
    wmsservers = getContentResolver().query(WMSLayerContentProvider.WMSLayerData.CONTENT_URI,
    null, selection, null, WMSLayerContentProvider.WMSLayerData.DEFAULT_SORT_ORDER);
    if (wmsservers != null){
    while (wmsservers.moveToNext()){
    WMSService wms = new WMSService(wmsservers.getString(WMSLayerContentProvider.WMSLayerData.BASEURL_CN));
    WMSLayer wmslayer = new WMSLayer(wms, wmsservers.getString(WMSLayerContentProvider.WMSLayerData.NAME_CN), wmsservers.getString(WMSLayerContentProvider.WMSLayerData.TITLE_CN));
    view.getOverlays().add(new WMSOverlay(wmslayer));
    }
    }
    } finally {
    if (wmsservers != null){
    wmsservers.close();
    }
    }
    }


No comments: