B4J Library jOpenStreetMaps library

Thanks to "WarWound" and his original library project "JfxtrasMapPane" in the post OSM Open Street Map for B4J back in 2014 which was based on the jfxtras 2.2 r5 source, I have been able to release this updated library.https://www.b4x.com/android/forum/threads/jopenstreetmaps-library.8

Bug fixes:
... Left mouse click now works. In fact all 3 mouse buttons are resolved.

Additions:
... Polygons can now be added/removed from map (MapPolygon class)
... Map tile providers have been updated.
... proper attributions for map tile providers have been added to the maps.
... now supports a local map cache for faster redraws.
... added a default Map Icon class containing ready to use icons (pins, car, truck, etc)
... map markers and can have their size, rotation, shadow set at initialisation.

Most Classes have been renamed and additional properties/functions added to classes.
... MapPane class is now OpenStreetMaps class.
... SimpleMapMarker class is now MapSpot class.
... MapLine is now MapPolyline.
... Initialisation functions for many classes have been changed and added.

Generally this library is a lot more friendly, in fact similar in a lot of ways to jGooleMaps library.

Just to note that the OpenStreetMap® is open data, licensed under the Open Data Commons Open Database License (ODbL) by the OpenStreetMap Foundation (OSMF).

Mapnik map tiles are released under LGPL (GNU Lesser General Public Licence v2.1).

The included map tile sets by © Stamen Design, are under a
Creative Commons Attribution (CC BY 3.0) license.

----------------------------------------------

Here is the new library "jOpenStreetMaps" now v1-03

for v1-03 changes refer to post #14 below.

I have also made available an example B4j project called "My OSM Demo".
The demo has also been updated to demonstrate some of the new features.
 

Attachments

  • My OSM Demo.zip
    57.1 KB · Views: 590
  • jOpenStreetMaps Library v1-03.zip
    138.1 KB · Views: 319
Last edited:

amorosik

Well-Known Member
Licensed User
Hi StarChild, I have tried the jOpenStreetMaps library and I think it is very effective
Thanks for sharing the code that will allow us to create interesting applications, and a question for the I have not yet found an answer
I use the OSM.Addmarker function to insert different markers and display a route
The code is used for single marker insertion

Private Pin As MapMarker
.....
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)
Pin.Title = date & "" & time
Pin.Description = runner_name
OSM.AddMarker (Pin)

Once the markers have been drawn, however, I cannot delete them from the map
I need help to understand:
1- how to delete all the markers on the map in one step
2- whether it is possible to selectively eliminate them, one by one
 

Starchild

Active Member
Licensed User
Hi StarChild, I have tried the jOpenStreetMaps library and I think it is very effective
Thanks for sharing the code that will allow us to create interesting applications, and a question for the I have not yet found an answer
I use the OSM.Addmarker function to insert different markers and display a route
The code is used for single marker insertion

Private Pin As MapMarker
.....
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)
Pin.Title = date & "" & time
Pin.Description = runner_name
OSM.AddMarker (Pin)

Once the markers have been drawn, however, I cannot delete them from the map
I need help to understand:
1- how to delete all the markers on the map in one step
2- whether it is possible to selectively eliminate them, one by one

To delete a marker try
OSM.RemoveMarker(ThisMarker)

When you add markers to the map you need to copy the marker into your own LIST of markers.
Then you can write a "For Each" loop to delete all markers in your LIST.

For my own application I created my own MARKER_TYPE containing the map marker and other related data about the marker for my program). My marker list was actually a list of my own MARKER_TYPE so I could track a better manage the markers on my map.

Hope this helps.
 

amorosik

Well-Known Member
Licensed User
To delete a marker try
OSM.RemoveMarker(ThisMarker)

When you add markers to the map you need to copy the marker into your own LIST of markers.
Then you can write a "For Each" loop to delete all markers in your LIST.

For my own application I created my own MARKER_TYPE containing the map marker and other related data about the marker for my program). My marker list was actually a list of my own MARKER_TYPE so I could track a better manage the markers on my map.

Hope this helps.

I don't need a list in my case because the information to create the marker is taken from the main db.
The same information is taken to remove the markers, but even after the removal cycle the markers remain in place

Do While MyRs.NextRow
.....
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)
Pin.Title = date & "" & time
Pin.Description = runner_name

If FLAG_VIEW Then
OSM.AddMarker (Pin)
else
OSM.RemoveMarker (Pin)
End If

Loop

So I'm sure that the data used for the creation of the marker is the same used for the removal
But the removal doesn't work
Is there perhaps some particular property in each marker to univocally identify it (and perhaps I have not really valued that one)?
 

DonManfred

Expert
Licensed User
But the removal doesn't work
sure it does not.

When you add the marker the first time you get a reference to this marker. Remember it in a Map or a List to be able to later remove the marker.
 

amorosik

Well-Known Member
Licensed User
Thank you for the reply
What mean exactly "..you get a reference to this marker .."
On the code below wich row must get a 'reference'?
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon) ?
OSM.AddMarker (Pin) ?
 

Starchild

Active Member
Licensed User
I don't need a list in my case because the information to create the marker is taken from the main db.
The same information is taken to remove the markers, but even after the removal cycle the markers remain in place

Do While MyRs.NextRow
.....
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)
Pin.Title = date & "" & time
Pin.Description = runner_name

If FLAG_VIEW Then
OSM.AddMarker (Pin)
else
OSM.RemoveMarker (Pin)
End If

Loop

So I'm sure that the data used for the creation of the marker is the same used for the removal
But the removal doesn't work
Is there perhaps some particular property in each marker to univocally identify it (and perhaps I have not really valued that one)?

As DomManfred said above, when you add a marker to the map you need to remember that marker (object) globally by also storing it somewhere else. You then use that stored reference to that marker (the original Object) in the RemoveMarker() function.
 

Starchild

Active Member
Licensed User
As an example...

In the Process_Globals section add
Private MyPin as MapMarker

In you code you wrote
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)
Pin.Title = date & "" & time
Pin.Description = runner_name
OSM.AddMarker(Pin)

Follow on with
MyPin = Pin

Later on you can delete that Pin using the Global reference to it.
OSM.RemoveMarker(MyPin)
 

amorosik

Well-Known Member
Licensed User
As DomManfred said above, when you add a marker to the map you need to remember that marker (object) globally by also storing it somewhere else. You then use that stored reference to that marker (the original Object) in the RemoveMarker() function.

I hope you will excuse me but I still don't understand
What do you mean exactly "..that stored reference to that marker .."?
Must this 'reference' be returned on the Pin.Initialize2 instruction or on the OSM.AddMarker instruction?
Each marker I draw is taken from the db, from a table that to simplify suppose it has three fields, code, latitude, longitude
How to draw or delete a marker corresponding to a row?
Where can i find an example or marker remove?
 

amorosik

Well-Known Member
Licensed User
I have modify with:

---------------------------------
Public array_marker(100000) As MapMarker ' codice <= 2000
....
Do While MyRs.NextRow
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)

If FLAG_VIEW Then
array_marker(codice)=Pin
OSM.AddMarker (Pin)
else
OSM.RemoveMarker (array_marker(codice))
End If

Loop
---------------------------------

Array of MapMarker,
But also with FLAG_VIEW = false the marker remain visible

1- MapMarker array definition
2- marker assignment to the 'code' position in the array, during AddMarker instruction
3- read marker from array on line 'code' during RemoveMarker instruction

It still doesn't work
Is it a mistake or is there an error?
 

Starchild

Active Member
Licensed User
I have modify with:

---------------------------------
Public array_marker(100000) As MapMarker ' codice <= 2000
....
Do While MyRs.NextRow
Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
Pin.SetCursor (fx.Cursors.HAND)

If FLAG_VIEW Then
array_marker(codice)=Pin
OSM.AddMarker (Pin)
else
OSM.RemoveMarker (array_marker(codice))
End If

Loop
---------------------------------

Array of MapMarker,
But also with FLAG_VIEW = false the marker remain visible

1- MapMarker array definition
2- marker assignment to the 'code' position in the array, during AddMarker instruction
3- read marker from array on line 'code' during RemoveMarker instruction

It still doesn't work
Is it a mistake or is there an error?

I think the problem is that the variable "codice" would need to be incremented when each Pin is created and added to your array. I can't tell what "codice" is or how it changes, from your example. I suspect that the same MapMarker (Pin) is being removed every time, and not all the other ones in the array.

Try this example.
B4X:
Public ListOfPins as list
....
ListOfPins.Initialize
....
Do While MyRs.NextRow
    'UID must be unique for this PIN only.  Every Pin must have its own UID value.
    Dim UID as string = ico_id   'I think "ico_id" is your unique identifier for this PIN
    'If you don't already, you may need to create one with every PIN and storing it on your database under its own column.
    'You possibly could use the RowNumber if you can read it, and the row numbers don't change for an existing PIN.
    If FLAG_VIEW Then
        Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
        AddPinToMap(Pin,UID)
    Else
        DeletePinFromMap(UID)
    End If
Loop
....
End Sub

Private sub AddPinToMap(ThisPin as MapMarker,Unique_ID as String)
    ThisPin.Tag = Unique_ID  'so you can find it later
    ThisPin.SetCursor(fx.Cursors.HAND)
    ListOfPins.Add(ThisPin)
    OSM.AddMarker(ThisPin)
End Sub

Private sub DeletePinFromMap(Unique_ID as String)
    Dim I as int
    if ListOfPins.Size > 0 Then
        For I = 0 to ListOfPins.Size-1
            Dim ThisPin as MapMarker = ListOfPins.Get(I)
            if ThisPin.Tag = Unique_ID then
                OSM.RemoveMarker(ThisPin)
                ListOfPins.RemoveAt(I)
                Return   'Pin was found and removed
            End If
        Next
    End If
End Sub

Private Sub DeleteAllPinsFromMap
    For Each P as MapMarker in ListOfPins
        OSM.RemoveMarker(P)
    Next
    ListOfPins.Clear
End Sub

I hope you can see the principle of creating a unique identifier for each Pin so it can be later removed from the map.
Good Luck

PS.

You could have a read about Objects (classes, creation/initialization/instantiation, pointers, etc).

In short, when a class in instantiated (lets say Initialized) a new unique instance of that class is Created in memory. This is an "Object". It can contain a collection of many things such as Code, Data, Images and even other objects, to form this new Object in memory.

The declaration of the variable (Dim Pin as MapMarker), once Initialized, is only a memory pointer to that newly created object (of MapMarker).

If you have another variable, say (Dim Abc as MapMarker) and we code (Abc = Pin) then both (Pin) and (Abc) reference the SAME object. They are just aliases for each other.
ie. the (Pin) memory pointer value is copied to (Abc)'s memory pointer.

In the example above (Sub AddPinToMap), adding the (Pin) to our "ListOfPins" is only storing the memory pointer to that (Pin) object into the list. The object itself is NOT copied. The "ListOfPins" contains a list of pointers to many different (Pin) Objects in memory.

When you pass an Object as a parameter to a function like; AddPinToMap(Pin,UID) the memory pointer of (Pin) is passed into the function so, that exact Pin can be accessed in memory, while the (UID) parameter (being a String) is copied, its current value is passed to the function, not (UID) itself.

I here you say, "I am Splitting Hairs" but the affect is that altering (ThisPin) inside the function makes changes to (Pin) in memory, while if you alter (Unique_ID) inside the function, then (UID) outside the function remains unaltered.

Other than standard variable types (Byte, Int, Long, Double, Float, String), and as a rule, if you need to (Initialize) it, then it is an Object and the variable is actually a pointer to it in memory.

If you declare your own TYPES and declare variables of these types, then they are also considered and treated as Objects, even if you choose not to call their Initialize() function.

If you get a compiler or run-time error of "Null Reference Pointer" this means that the variable does not point to an object in memory. It probably has not been Initialized yet. Its pointer holds the value of "Null".

Removing a (Pin) Object from the list and map does not delete it from memory yet, even though you are no longer showing it, or using it. It's only when ALL variables that were pointing to (Referenced) the object are them selves overwritten or no longer required (eg inside a sub-function) that the Object in memory becomes "De-referenced". The memory manager (garbage Collector) in the language environment will come along later and remove it from memory "Destroy It", as and when required. You don't need to worry about it.

Happy coding....
 
Last edited:

amorosik

Well-Known Member
Licensed User
I think the problem is that the variable "codice" would need to be incremented when each Pin is created and added to your array. I can't tell what "codice" is or how it changes, from your example. I suspect that the same MapMarker (Pin) is being removed every time, and not all the other ones in the array.

Try this example.
B4X:
Public ListOfPins as list
....
ListOfPins.Initialize
....
Do While MyRs.NextRow
    'UID must be unique for this PIN only.  Every Pin must have its own UID value.
    Dim UID as string = ico_id   'I think "ico_id" is your unique identifier for this PIN
    'If you don't already, you may need to create one with every PIN and storing it on your database under its own column.
    'You possibly could use the RowNumber if you can read it, and the row numbers don't change for an existing PIN.
    If FLAG_VIEW Then
        Pin.Initialize2 ("Id_row", ico_id, 75,0,5, lat, lon)
        AddPinToMap(Pin,UID)
    Else
        DeletePinFromMap(UID)
    End If
Loop
....
End Sub

Private sub AddPinToMap(ThisPin as MapMarker,Unique_ID as String)
    ThisPin.Tag = Unique_ID  'so you can find it later
    ThisPin.SetCursor(fx.Cursors.HAND)
    ListOfPins.Add(ThisPin)
    OSM.AddMarker(ThisPin)
End Sub

Private sub DeletePinFromMap(Unique_ID as String)
    Dim I as int
    if ListOfPins.Size > 0 Then
        For I = 0 to ListOfPins.Size-1
            Dim ThisPin as MapMarker = ListOfPins.Get(I)
            if ThisPin.Tag = Unique_ID then
                OSM.RemoveMarker(ThisPin)
                ListOfPins.RemoveAt(I)
                Return   'Pin was found and removed
            End If
        Next
    End If
End Sub

Private Sub DeleteAllPinsFromMap
    For Each P as MapMarker in ListOfPins
        OSM.RemoveMarker(P)
    Next
    ListOfPins.Clear
End Sub


Happy coding....

Many thanks for your help
The code now run correctly
But not very fast (almost as i expected), for about 200 marker => 10 sec (Win10, i7, ssd, 16Gb ram)
Any idea how to optimize for faster response?
 

Starchild

Active Member
Licensed User
Many thanks for your help
The code now run correctly
But not very fast (almost as i expected), for about 200 marker => 10 sec (Win10, i7, ssd, 16Gb ram)
Any idea how to optimize for faster response?

I'm not sure if it will help.
You could try making the MapMarkers Invisible first before you remove it, or
Make the OSM itself invisible, remove markers, then make it visible again.

Always a problem when changing lots of things at the same time, on the OSM library.
 

Ralph Parkhurst

Member
Licensed User
IU wonder if it is possible to enable a "smoother" form of map scrolling, particularly whilst the mouse button is held down - like the way Google Maps does it?

OSM only seems to move the map when the mouse is released.

Also, a map move shows blue rotating circles on my screen - is this normal behavior?

Many thanks,
Ralph
 

Starchild

Active Member
Licensed User
IU wonder if it is possible to enable a "smoother" form of map scrolling, particularly whilst the mouse button is held down - like the way Google Maps does it?

OSM only seems to move the map when the mouse is released.

Also, a map move shows blue rotating circles on my screen - is this normal behavior?

Many thanks,
Ralph

The method of map move is governed by the underlying MapPane library that has been wrapped.
MapPane does not support smooth map moving.

The blue rotating circles are indicating that that map tile is currently being fetched from the osm map server. Once the map tile arrives it is displayed and the rotating circle is removed. If the map tile already exists locally in the map cache then that map tile is displayed without any rotating circle.

I have continued to develop the OSM library for my own projects. If you would like to evaluate my osm library then start a "Conversation" with me making this request.
 
Top