Android Tutorial OSMDroid - MapView for B4A tutorial

You can find the OSMDroid library thread here: http://www.b4x.com/forum/additional...tes/16309-osmdroid-mapview-b4a.html#post92643.

AIM: Create and initialize a MapView, enable the map zoom controller and multitouch controller, set a zoom level then center the map on a location.

B4X:
Sub Process_Globals
End Sub

Sub Globals
   Dim MapView1 As MapView
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If File.ExternalWritable=False Then
      '   OSMDroid requires the use of external storage to cache tiles
      '   if no external storage is available then the MapView will display no tiles
      Log("WARNING NO EXTERNAL STORAGE AVAILABLE")
   End If
   
   '   no EventName is required as we don't need to listen for MapView events
   MapView1.Initialize("")
   Activity.AddView(MapView1, 0, 0, 100%x, 100%y)
   
   '   by default the map will zoom in on a double tap and also be draggable - no other user interface features are enabled
   
   '   enable the built in zoom controller - the map can now be zoomed in and out
   MapView1.SetZoomEnabled(True)
   
   '   enable the built in multi touch controller - the map can now be 'pinch zoomed'
   MapView1.SetMultiTouchEnabled(True)
   
   '   set the zoom level BEFORE the center (otherwise unpredictable map center may be set)
   MapView1.Zoom=14
   MapView1.SetCenter(52.75192, 0.40505)
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

The code is pretty self-explanatory.

I've added the code to check if the device has available external storage as OSMDroid will not display any tiles if no external storage is available.
External storage is used to save/cache all downloaded tiles - no external storage means no map!
(I'll omit that check from future tutorials but it's something to bear in mind - not that i know of any Android devices that have no external storage).

Create and initialize a MapView, add it to the Activity 100% width and 100% height.
Enable the zoom and multi-touch controller.
Zoom in to level 14 then set the MapView center to a location (sunny Norfolk, UK!).

I've found that setting the map center and then immediately setting the zoom level does not work as expected.
I think that while the MapView is setting the map center it also zooms in so the end result is unpredictable.

Pan and zoom the map, now rotate your device and you'll see the map returns to it's initial state of zoom level 14, center (52.75192, 0.40505).

I shall show you how to save and restore the MapView state next...

Martin.
 

Attachments

  • 01 - SimpleMap.zip
    5.8 KB · Views: 4,809
Last edited:

GaNdAlF89

Active Member
Licensed User
Longtime User
Hi, I use a mapview to show the current position (with latitude and longitude) of device from gps. In this map I added a pushpin centered in the map. I want that user can not move the map, but only see where he is; i.e. the user can only see the map like it is an image. How can I do this? Thanks!
 

warwound

Expert
Licensed User
Longtime User
Hi, I use a mapview to show the current position (with latitude and longitude) of device from gps. In this map I added a pushpin centered in the map. I want that user can not move the map, but only see where he is; i.e. the user can only see the map like it is an image. How can I do this? Thanks!

There's no option in OSMDroid to disable all map movement.
You can use SetZoomEnabled(False) and setMultiTouchZoomEnabled(False) but the user can still pan the map by touching it and a double tap will zoom in.
(No way to zoom out though i think).

A solution might be to place a Panel over the MapView and add a touch listener to the Panel.
The touch listener would have to do nothing more than return a True value to indicate that it had 'consumed' the touch event.
The touch event wouldn't then propogate down the layers of Views to the MapView.

Martin.
 

GaNdAlF89

Active Member
Licensed User
Longtime User
There's no option in OSMDroid to disable all map movement.
You can use SetZoomEnabled(False) and setMultiTouchZoomEnabled(False) but the user can still pan the map by touching it and a double tap will zoom in.
(No way to zoom out though i think).

A solution might be to place a Panel over the MapView and add a touch listener to the Panel.
The touch listener would have to do nothing more than return a True value to indicate that it had 'consumed' the touch event.
The touch event wouldn't then propogate down the layers of Views to the MapView.

Martin.
Thanks Martin, I had tried to add a panel over the map, but without consuming the touch event! Thanks!!
 

Spectre

Active Member
Licensed User
Longtime User
No.

It'll interpolate a great circle from one GeoPoint to another - that's all.
You'll need to use a PathOverlay and some basic geometry.

Martin.
ok ... Martin, if I wanted to draw circles to indicate the distance from my point (eg every 100 meters x 5 circles) do you have any idea?
best regards...
Spectre
 

warwound

Expert
Licensed User
Longtime User
ok ... Martin, if I wanted to draw circles to indicate the distance from my point (eg every 100 meters x 5 circles) do you have any idea?
best regards...
Spectre

Looking at the OSMDroid source code this would have to be implemented as a new Overlay - let's say we'll call it a CircleOverlay.
A CircleOverlay would extend the java Overlay class.
It's draw method is called when a draw is required and the draw method is passed a Canvas object to draw on.

So could i create a new CircleOverlay object and enable it to draw one or more circles...?

I'll take a look a bit later or over the weekend.

Martin.
 

Spectre

Active Member
Licensed User
Longtime User
Looking at the OSMDroid source code this would have to be implemented as a new Overlay - let's say we'll call it a CircleOverlay.
A CircleOverlay would extend the java Overlay class.
It's draw method is called when a draw is required and the draw method is passed a Canvas object to draw on.

So could i create a new CircleOverlay object and enable it to draw one or more circles...?

I'll take a look a bit later or over the weekend.

Martin.

you ... nice idea ... You could use the properties of the map scale to fit when you zoom ... This function is convenient see immediately on the basis of the distances of the WP circles on the map.

for now I thought I would draw circles on panel put on the map, derive the distances to draw circles from the geopoints projected from the center of the map ...

One thing in this version it is possible to use custom icons for the GPS position of the cursor?
 

warwound

Expert
Licensed User
Longtime User
Just had time to put a simple CircleOverlay together - take a look here: http://b4a.martinpearman.co.uk/osmdroid/CircleOverlay-alpha-20140502.zip.

The circles are hardcoded to red with a stroke width of 2 pixels.
And the circle radius are defined in units of pixels - so zoom in and out and the circles remain the same size.

I'll need to have a little think about using meters as the radius units - shouldn't be too much work.

The GPS pegman is hardcoded into the java android OSMDroid library - but i'll look at that too and see if it can modified.

Martin.
 

warwound

Expert
Licensed User
Longtime User
I've now updated the CircleOverlay example from my previous post.
It allows you to set the circle color and stroke width as well as the radius.
Link is the same as before.

Martin.
 

warwound

Expert
Licensed User
Longtime User
And updated once again - the circle radius is now units of meters not pixels.
I've added a ScaleBarOverlay to the demo code and the circle radius seems to match what the ScaleBarOverlay says.

@Spectre Give it a test and let me know what you think - any ideas to improve it welcome.

Martin.
 

Spectre

Active Member
Licensed User
Longtime User
And updated once again - the circle radius is now units of meters not pixels.
I've added a ScaleBarOverlay to the demo code and the circle radius seems to match what the ScaleBarOverlay says.

@Spectre Give it a test and let me know what you think - any ideas to improve it welcome.

Martin.
Hi Martin ...
I try I doubt the version ... I hope I never have problems because the stairs overlay can not see it with the version of the SDK that I use.
You are doing a fantastic job...
 

Spectre

Active Member
Licensed User
Longtime User
Ok ... It also works well with hardware acceleration enabled.
You can see the two screen shots.
One thing: to calculate the actual distance in meters making circles if possible I would change the RADIUS parameter putting the distance in meters of the circle with respect to the central point.
Otherwise, you need to calculate is not easy as point.

Ex: CircleOverlay1.AddCircleItem (InitialGeoPoint, 64dip, 2dip, Colors.Red)

CircleOverlay1.AddCircleItem (Lat, Lon, meter to center, stroke, Colors)
 

Attachments

  • Screenshot_2014-05-03-10-30-16.png
    Screenshot_2014-05-03-10-30-16.png
    206.8 KB · Views: 712
  • Screenshot_2014-05-03-10-30-42.png
    Screenshot_2014-05-03-10-30-42.png
    46.5 KB · Views: 401

Spectre

Active Member
Licensed User
Longtime User
Hi!
I noticed one thing ... the circles as told to fit the zoom and scaleoverlay.
In some cases, however, no good example as I said if we turn use them to indicate the fixed distances from the center of the map.
In this case, they just shrink when it zooms in and does not fit the scale ..
I hope I've explained it well ...
 

IslamQabel

Active Member
Licensed User
Longtime User
When i run example no 6, an error message is displayed as follows:
An error has occurred in sub:
java.lang.IllegalArgumentException: Resource not found: /resources/org/osmdroid/person.png

How to overcome this problem?

Thanks
 

IslamQabel

Active Member
Licensed User
Longtime User
for post number 151, when i run the application, an error message appears as follows:
an error has occurred in sub:
java.lang.IllegalArgumentException:Resource not found:/resources/org/osmdroid/marker_default.png
 

IslamQabel

Active Member
Licensed User
Longtime User
For example: (06-overlaysimpleexample)
Error message appears when i run the application, although i did as you said in this paragraph
"The MyLocationOverlay requires the resources in the drawable-nodpi folder that is included with the library download. Copy the drawable-nodpi to your project's Objects/res folder and ensure that all files in that folder are set to read-only" and i make sure that all files are read-only
The error message is displayed as follows:
"java.lang.IllegalArgumentException: Resource not found: /resources/org/osmdroid/person.png"
 

Spectre

Active Member
Licensed User
Longtime User
For example: (06-overlaysimpleexample)
Error message appears when i run the application, although i did as you said in this paragraph
"The MyLocationOverlay requires the resources in the drawable-nodpi folder that is included with the library download. Copy the drawable-nodpi to your project's Objects/res folder and ensure that all files in that folder are set to read-only" and i make sure that all files are read-only
The error message is displayed as follows:
"java.lang.IllegalArgumentException: Resource not found: /resources/org/osmdroid/person.png"


Hi
it is likely that you have not copied into the folder / res files you need. Look here to see post # 6.

http://www.b4x.com/android/forum/threads/osmdroid-mapview-for-b4a-tutorial.16310/#post92644
 

warwound

Expert
Licensed User
Longtime User
Hi!
I noticed one thing ... the circles as told to fit the zoom and scaleoverlay.
In some cases, however, no good example as I said if we turn use them to indicate the fixed distances from the center of the map.
In this case, they just shrink when it zooms in and does not fit the scale ..
I hope I've explained it well ...

Google Translate isn't helping much lol!
Can you explain your question again?

Do you want circles with a fixed pixel defined radius or circles with a meter defined radius?

Pixels = the circle will have the same size in pixels at all zoom levels.
Meters = the circle size will vary according to the current zoom level.
(Meters are converted to pixels for each zoom level based on the number of pixel per meter at the equator).

Martin.
 

Spectre

Active Member
Licensed User
Longtime User
Google Translate isn't helping much lol!
Can you explain your question again?

Do you want circles with a fixed pixel defined radius or circles with a meter defined radius?

Pixels = the circle will have the same size in pixels at all zoom levels.
Meters = the circle size will vary according to the current zoom level.
(Meters are converted to pixels for each zoom level based on the number of pixel per meter at the equator).

Martin.

Sorry Martino, it's my fault and my English is horrible ...

I used to meter the circles indicate the distance in meters from the center point.

I can then lock the zoom on my case...

Circle shows the WP 200 meters in radius of 200 meters.
Circle shows the WP 600 meters in radius of 600 meters.
etc.. etc..

But I think it's not a problem you could put both options in order to adapt to all your needs.
 

warwound

Expert
Licensed User
Longtime User
How about this...

  • OSMDroid_CircleOverlay
    Fields:
    • RADIUS_UNITS_TYPE_METERS As RadiusUnitsType
    • RADIUS_UNITS_TYPE_PIXELS As RadiusUnitsType
    Methods:
    • AddCircleOverlayItem (Center As GeoPoint, Radius As Float, RadiusUnitsType1 As RadiusUnitsType, StrokeWidth As Float, StrokeColor As Int) As CircleOverlayItem
      Creates, adds and return a CircleOverlayItem object.
    • AddCircleOverlayItem2 (Latitude As Double, Longitude As Double, Radius As Float, RadiusUnitsType1 As RadiusUnitsType, StrokeWidth As Float, StrokeColor As Int) As CircleOverlayItem
    • ClearCircleOverlayItems
      Clear the CircleOverlay of all CircleOverlayItems.
    • GetBoundingBox As BoundingBox
      Returns a BoundingBox that represents the area covered by the centers of all CircleOverlayItems.
    • Initialize
    • IsInitialized As Boolean
    • RemoveCircleOverlayItem (CircleOverlayItem1 As CircleOverlayItem) As Boolean
      Remove CircleOverlayItem1 from the CircleOverlay.
      Return True on success otherwise False.
  • OSMDroid_CircleOverlayItem
    Fields:
    • FILL As Style
      Geometry and text drawn with this style will be filled, ignoring all stroke-related settings in the paint.
    • FILL_AND_STROKE As Style
      Geometry and text drawn with this style will be both filled and stroked at the same time, respecting the stroke-related fields on the paint.
    • STROKE As Style
      Geometry and text drawn with this style will be stroked, respecting the stroke-related fields on the paint.
      This is the CircleOverlayItem default.
    Properties:
    • Center As GeoPoint
    • Radius As Float
    • RadiusUnitsType As RadiusUnitsType
    • StrokeColor As Int
    • StrokeStyle As Style
    • StrokeWidth As Float
    • Tag As Object
The CircleOverlay displays CircleOverlayItems - a CircleOverlayItem has a center, radius, stroke width, stroke color, stroke type and Tag property.
The CircleOverlay methods AddCircleOverlayItem and AddCircleOverlayItem2 create, add and return a CircleOverlayItem.
That reference to the CircleOverlayItem can be used to remove it from the overlay using the method RemoveCircleOverlayItem.

All CircleOverlayItem properties can be modified at runtime though you'll need to call the MapView Invalidate method to see any modifications applied.

You can set a CircleOverlayItem radius in units of pixels (fixed size circle) or meters (circle size depends on zoom level).
You can choose the stroke style (same as PathOverlay) of FILL, FILL_AND_STROKE or STROKE.
And the CircleOverlay now has a GetBoundingBox method.

Updated library files and demo b4a project can be downloaded from here: http://b4a.martinpearman.co.uk/osmdroid/CircleOverlay-20140505.zip.

Martin.
 
Top