The application is available here
Android GIS
Monday, 14 November 2011
Thursday, 11 August 2011
ArcGIS Android - Persisting map state
ESRI documentation describes how to use onRetainNonConfigurationInstance for handling map rotation so that the scale, centre and layer state of the map is saved when onCreate is called (e.g http://help.arcgis.com/en/arcgismobile/10.0/apis/android/help/#/My_first_application/011900000005000000/)
While this works fine I would like my application to remember map setting not only when the phone is rotated, but also when the user closes and re-enters the application. For this to work I save the map state values to the PreferenceManager like this when app is paused:
@Override protected void onPause() { super.onPause(); SharedPreferences settings = getSharedPreferences("mapPreference", 0); SharedPreferences.Editor ed = settings.edit(); ed.putString("mapstate", map.retainState()); ed.commit(); }And then retrieve the map settings in the onCreate method:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // get the map settings SharedPreferences settings = getSharedPreferences("mapPreference", 0); String mapState = settings.getString("mapstate", null); if (mapState != null){ map.restoreState(mapState); }
Tuesday, 9 August 2011
ArcGIS - Cascading WMS is a No-Go
So I wanted to add geographic information to the geological map. I have access to a long series of a nice WMS at http://www.kortforsyningen.dk/ which would be an excellent option. But alas, it is not possible with the ArcGIS server to publish a WMS based on a mxd-file that includes a WMS: http://support.esri.com/en/knowledgebase/techarticles/detail/35903.
This is pretty annoying - Cascading a WMS would be no problem if I had used MapServer. Well, now I am married to ESRI so I have to suffer the consequences...
Instead I found a georeferenced map image that I put on a transparent layer and add it on top of the geological map layer. Result is not as nice as it would have been if I could have used WMS from kortforsyningen but it is usable:
This is pretty annoying - Cascading a WMS would be no problem if I had used MapServer. Well, now I am married to ESRI so I have to suffer the consequences...
Instead I found a georeferenced map image that I put on a transparent layer and add it on top of the geological map layer. Result is not as nice as it would have been if I could have used WMS from kortforsyningen but it is usable:
Friday, 22 July 2011
ArcGIS for Android
As per previous post, I was playing around with Google Map and overlays. I found this link to put geometries on top of Google map in an AsyncTask: http://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/, but it seems much more difficult to add WMS on top of Google maps using an AsyncTask....
Alright, so I found out that ESRI is developing an API for Android: http://resources.arcgis.com/content/arcgis-android/api. The samples look nice and I decided to give it a go, especially since my work place uses ESRI products. The presentation DS2011: Introduction to ArcGIS API for Android gives nice and detailed information on how to install the eclipse plugin and get started using the API. After a days work, I feel pretty sure that I will base my application on the ESRI API.
Here is how far I have gotten:
First of all I published a new WMS on our ArcGis Server: http://geuswebgis01.geus.dk:8399/arcgis/rest/services/Danmarksgeologi/j200/MapServer. The WMS renders the geological map of Denmark at scale 1:200.000.
Here is how to add the WMS in the layout file (lines 7-13):
Panning and zooming works really well. Now it is time to explore the remaining parts of the ESRI Android API...
Alright, so I found out that ESRI is developing an API for Android: http://resources.arcgis.com/content/arcgis-android/api. The samples look nice and I decided to give it a go, especially since my work place uses ESRI products. The presentation DS2011: Introduction to ArcGIS API for Android gives nice and detailed information on how to install the eclipse plugin and get started using the API. After a days work, I feel pretty sure that I will base my application on the ESRI API.
Here is how far I have gotten:
First of all I published a new WMS on our ArcGis Server: http://geuswebgis01.geus.dk:8399/arcgis/rest/services/Danmarksgeologi/j200/MapServer. The WMS renders the geological map of Denmark at scale 1:200.000.
Here is how to add the WMS in the layout file (lines 7-13):
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.esri.android.map.MapView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.esri.android.map.ags.ArcGISDynamicMapServiceLayer url="http://geuswebgis01.geus.dk:8399/arcgis/rest/services/Danmarksgeologi/j200/MapServer"/> </com.esri.android.map.MapView> <RelativeLayout android:id="@+id/InnerRelativeLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" > <Button android:text="Settings" android:id="@+id/settingsbutton" android:layout_height="wrap_content" android:layout_width="wrap_content"> </Button> <Button android:text="Nyheder" android:id="@+id/nyhederbutton" android:layout_toRightOf="@+id/settingsbutton" android:layout_height="wrap_content" android:layout_width="wrap_content"> </Button> </RelativeLayout> </RelativeLayout>
Panning and zooming works really well. Now it is time to explore the remaining parts of the ESRI Android API...
Wednesday, 20 July 2011
Adding a WMS to google maps
Here is my first working version of an Android application in which the user can see and interact with a Web Map Service (WMS), that shows geological information for Denmark. The WMS is described here: http://geusjuptest.geus.dk/OneGeologyEurope/
The geological WMS is shown using Google Maps.
Here is the Activity class that displays the google map as well as the WMS (i.e. the myOverlay object)
The WMS overlay extends the com.google.android.maps.Overlay Class. In the draw method the WMS is defined (i.e. the WMSLoader class):
The only missing piece is the WMSLoader class - Here it is:
And then finally the little MapUtils helper class:
The geological WMS is shown using Google Maps.
Here is the Activity class that displays the google map as well as the WMS (i.e. the myOverlay object)
package dk.geus; import java.util.List; import android.os.Bundle; import android.preference.PreferenceManager; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapActivity; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; public class Map01 extends MapActivity { private MapView mapView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.map); mapView = (MapView)findViewById(R.id.map_view); MapController mapController = mapView.getController(); mapController.setCenter(new GeoPoint(55700000, 12600000)); mapController.setZoom(10); mapView.setClickable(true); mapView.setEnabled(true); mapView.setBuiltInZoomControls(true); /* MyLocationOverlay myLocOverlay = new MyLocationOverlay(this, mapView); myLocOverlay.enableMyLocation(); mapView.getOverlays().add(myLocOverlay);*/ Listoverlays = mapView.getOverlays(); WMSOverlay myOverlay = new WMSOverlay(); boolean lithologyClicked = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("lithologyClicked", true); if (lithologyClicked){ overlays.add(myOverlay); } mapView.postInvalidate(); } @Override protected boolean isRouteDisplayed() { // TODO Auto-generated method stub return false; } }
>package dk.geus; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; public class WMSOverlay extends Overlay { @Override public void draw(Canvas canvas, MapView mapView, boolean shadow) { super.draw(canvas, mapView, shadow); WMSLoader wmsclient = new WMSLoader(); GeoPoint[] cornerCoords = MapUtils.getCornerCoordinates(mapView.getProjection(), canvas); Bitmap image = wmsclient.loadMap(canvas.getWidth(), canvas.getHeight(), cornerCoords[0], cornerCoords[1]); Paint semitransparent = new Paint(); semitransparent.setAlpha(0x888); canvas.drawBitmap(image, 0, 0, semitransparent); } }
The only missing piece is the WMSLoader class - Here it is:
package dk.geus; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import com.google.android.maps.GeoPoint; public class WMSLoader { public static String TAG = "WMSLoader Exception"; public Bitmap loadMap(int width, int height, GeoPoint ul, GeoPoint lr) { URL url = null; try { // http://geusjuptest.geus.dk/oneGEconnector/?service=WMS&version=1.1.1&styles=default&request=GetMap&layers=OGE_1M_surface_GeologicUnit&width=2000&height=2000&bbox=7,54,15.5,58&format=image/png&srs=epsg:4326 url = new URL(String.format("http://geusjuptest.geus.dk/oneGEconnector/?" + "LAYERS=OGE_1M_surface_GeologicUnit&TRANSPARENT=true&FORMAT=image/png&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=default&EXCEPTIONS=application/vnd.ogc.se_inimage&SRS=EPSG:4326" + "" + "&BBOX=%f,%f,%f,%f&WIDTH=%d&HEIGHT=%d", MapUtils.longitude(ul), MapUtils.latitude(lr), MapUtils.longitude(lr), MapUtils.latitude(ul), width, height)); } catch (MalformedURLException e) { Log.e(TAG, e.getMessage()); } InputStream input = null; try { input = url.openStream(); } catch (IOException e) { Log.wtf(TAG, "****************** Error in WMSLoader: " + e.getMessage()); } return BitmapFactory.decodeStream(input); } }
And then finally the little MapUtils helper class:
package dk.geus; import android.graphics.Canvas; import com.google.android.maps.GeoPoint; import com.google.android.maps.Projection; public class MapUtils { static float longitude(GeoPoint point){ return (float) (point.getLongitudeE6()/1e6); } static float latitude(GeoPoint point){ return (float) (point.getLatitudeE6()/1e6); } static GeoPoint[] getCornerCoordinates(Projection projection,Canvas canvas){ GeoPoint[] geoPoint = new GeoPoint[2]; geoPoint[0]= projection.fromPixels(0, 0); geoPoint[1]= projection.fromPixels(canvas.getWidth() - 1, canvas.getHeight() - 1); return geoPoint; } }
Subscribe to:
Posts (Atom)