[MapPane] Load in a background thread

57 views
Skip to first unread message

François Guillot

unread,
Nov 30, 2013, 12:48:47 PM11/30/13
to jfxtra...@googlegroups.com
Hi guys,

For my Java FX app, I need to display a lot of MapMarkers on my map.

In order to accelerate the map loading, I downloaded the Tiles for the Area I'm interested in, and I use LocalTileSourceFactory.
This works perfectly.

I need to display 10 000 markers on the map.
For each marker that I creates, I call 
MapPane#addMapLayer(Renderable layer)
to add the marker on the ObservableList<Renderable> mapLayers attribute of the MapPane.
This also works, but each time the above methode is called, the RenderChangeListener is called to re-render the map.

This is time consuming (even for a single marker), so it is very very time consuming for my 10 000 markers.
Since this is done on the Java FX Application Thread, it blocks the UI for several seconds.

I tried to implement a custom javafx.concurrent.Task subclass, to perform all the expensive computation in a background thread.
But this fails because at some point, the RenderChangeListener  is called (for each marker) and it needs to do its work on the UI Thread, so I get an exception (that actually kills my background thread)

So I have several questions :

1°) Why is it necessary to render everything when adding a MapMarker ?
RenderChangeListener calls renderControl(), which renders the map + the layers + the attributions

2°) Can I prevent the map from being rendered when iterating on my 10 000 map markers, and only perform one full render at the end ? This will probably save time

3°) How can I add 10 000 markers on a background thread, while the expansive computation (i.e. the marker rendering) needs to be done on the UI thread ?


Thanks for your insights !

François

François Guillot

unread,
Nov 30, 2013, 2:14:46 PM11/30/13
to jfxtra...@googlegroups.com
Hi

I found the MapPane#setIgnoreRepaint(boolean ignoreRepaint) method.

So I set it to false before adding my markers and then back to true at the end.
Si I guess the app only does one big rendering when everything is added (in the UI Thread)
But even like that, it freezes the UI (for 2 seconds) when scrolling / moving the map
And it takes 3-4 seconds the render the map initially.

Did I miss something ?

Thanks
François

François Guillot

unread,
Dec 3, 2013, 7:13:10 AM12/3/13
to jfxtra...@googlegroups.com
Hi,

I found the root of the problem.
When "rendering" an AbstractMapMarker, the code only adds it to the tilesGroup Group of the MapPane component.
So the mapPane ends up with a Children list filled with all the tiles group + all the markers.
The Quantum Renderer thread tries to draw all these children, and only at that time, it tries to intersect each marker's bounds with the clipMask of the map pane component.
So this intersection check must be done for the 10 000 markers, everytime.

In the AbstractMapMarker#render method

I added
if(node.getBoundsInParent().intersects(mapController.getClipMask().getLayoutBounds()))
before actually adding the node to the tilesGroup children list.

So even with 10 000 markers, only the one intersectings with the current mask are added, wich makes the rendering much faster (espacially when at the end you only have a few markers in your area of interest !)

What do you think of this ?

John Childress

unread,
Dec 7, 2013, 9:00:04 AM12/7/13
to jfxtra...@googlegroups.com
Thank you for sharing this and your other tip/experience with MapPane.  It was very helpful.

John
Reply all
Reply to author
Forward
0 new messages