Opened 9 years ago
Last modified 8 years ago
#13030 new enhancement
Allow the creation of two map views
Reported by: | michael2402 | Owned by: | team |
---|---|---|---|
Priority: | normal | Milestone: | |
Component: | Core | Version: | |
Keywords: | gsoc-core | Cc: | Don-vip, bastiK, stoecker |
Description (last modified by )
The main goal of this ticket is to allow the creation and use of two map views. It is a central place to collect things preventing us from using multiple map views.
So far, those are the main problems for displaying the same layers twice:
- Main.map.mapView.repaint() or Main.map.repaint() calls. They can be traced using the --trace option. The stach trace triggering such a repaint will be dumped. Layers should simply invalidate their layer. Use #12654
- undo does not trigger a layer invalidated
Layer.isChanged()
cannot be used with multiple map views. Map view needs to track changes by itself using the invalidation events- AbstractTileSourceLayer needs to be changed to use one TileSet per MapView.
Displaying different layers:
- The layer list is already prepared to work with multiple layer managers.
- Many layers assume they are only added/removed once to a layer manager (AbstractTileSourceLayer, ValidatorLayer, MarkerLayer, ...). #12872 might solve this for implicitly added layers.
Editing in the second view will be much harder, because:
- MapModes assume there is only one map view
This works:
- Creating a second MapView
- Moving and zooming the map
- Display a data layer
- Display selection
Attachments (1)
Change History (14)
by , 9 years ago
Attachment: | mapview-window.png added |
---|
comment:1 by , 9 years ago
Description: | modified (diff) |
---|
follow-up: 3 comment:2 by , 9 years ago
follow-up: 4 comment:3 by , 9 years ago
Replying to wiktorn:
What is the goal:
- to have a multiple
MapView
s that share the same layers- or, to have multiple
MapView
s that have different layer sets shown- or to have multiple
MapView
s that show different part of the map
I want to support all three goals. The main idea is to allow plugins to use map views when they need it. I can imagine several use cases:
- Add a real map view that follows the main view to the side panel instead of the current minimap
- Split the main map view, show different background on each
- Split the main map view, show different parts of the map (they may even be synced but e.g. with other zoom level)
- Add a map view to a dialog. We can ask the user which way to split by simply showing the area around that node and asking the user to select the way instead of just complaining like we do now.
- Allow layers to exist and tests to run without the need of a MapView.
What I don't want is to only support different layers in the MapViews. I don't see that much advantage of it - we already have a flexible slippy map and if you want to edit two layers, simply apply the Copy+Paste patch and use two JOSM instances ;-).
From what I understand, what you wrote, you want to have as much flexibility as possible, but on the other hand - use the same Layer instances in all
MapView
s. As this is really good for all editable layers, in case of background imagery tiles it introduces a lot more problems than only making TileSet local to MapView.
tileCache
/MemoryTileCache
inAbstractTileSourceLayer
is crucial for performance of imagery paint. On the other hand, it's one of the biggest memory consumers in JOSM- Right now, MemoryTileCache is sized based on screen resolution, with multiple MapViews, we would like to estimate the cache size based on maximum (or maybe - current) MapView size, so we won't use more memory than needed
- If we will use the same
Layer
instance in different zoom levels, then they will be competing for the cache entries raising the risk of cache misses and hindering performance (though the risk is not that big, as we reserve some place for tiles from lower zoom levels - for tile substitution during load)- If we will use the same
Layer
instance showing different part of the map - then frequent cache misses will be inevitable, thus I would not recommend this approach.- If user adds the same layer twice to JOSM, we will duplicate memory use, as we will store the same element twice. But on the other hand, if the layers are at different zoom level, they actually store different entries.
We can use two-layered approach to memory cache, and do the LRU in one Map, that refers to other Map, that's common to all caches to reduce memory footprint. Though this not free us to have one
Layer
, that shows different part of itself in different MapViews.
Maybe this (i.e. tileCache + TileSet, and all things dependant on current view of the map) is something, that needs extraction to different class.
This is why I added the LayerPainter
class. You can create a new layer painter for each map view your layer is attached to. This is similar to your two-layer approach but more abstract in that the user does not see it. Basically, the AbstractTileSourceLayer will just be a factory for the LayerPainter
that does all work the normal layer does now. The settings are still contained in the AbstractTileSourceLayer and will be shared by all painters.
The LayerPainter
may even get more state in the future, I could think of something like the Android onPause
/onResume
. This would allow us to handle hidden MapViews or hidden Layers without releasing all data but e.g. setting a soft reference to it. But this is an optimization that I am not planing at the moment.
That way, you can have two independent tile caches/tile sets for now. We can attempt to optimize this later but I would like to not experiment until we have a real use case where cache size is a problem.
comment:4 by , 9 years ago
Replying to michael2402:
This is why I added the
LayerPainter
class. You can create a new layer painter for each map view your layer is attached to. This is similar to your two-layer approach but more abstract in that the user does not see it. Basically, the AbstractTileSourceLayer will just be a factory for theLayerPainter
that does all work the normal layer does now. The settings are still contained in the AbstractTileSourceLayer and will be shared by all painters.
The
LayerPainter
may even get more state in the future, I could think of something like the AndroidonPause
/onResume
. This would allow us to handle hidden MapViews or hidden Layers without releasing all data but e.g. setting a soft reference to it. But this is an optimization that I am not planing at the moment.
That way, you can have two independent tile caches/tile sets for now. We can attempt to optimize this later but I would like to not experiment until we have a real use case where cache size is a problem.
I haven't seen the code yet, but I guess that our thoughts go into the same direction.
Just to have some number at hand - AbstractTileSourceLayer.estimateMemoryUsage()
gives 38.5MB when using 2560x1440 screen. For some of the workflows I was using ~6 different background imageries at once, which gives 240MB memory for cache right now, and 480MB in case we are having two MapView
s. In case of minimap I guess we could dramatically reduce the size of the cache knowing that window is showing no more than 4 (or whatever the number is) tiles at one time which reduces memory usage to 1MB of memory.
It would be terrific if we could maintain functionality of estimateMemoryUsage()
which is used mainly to warn the user that he has added so many layers that he will run to OutOfMemory exception when they will get filled. So we give him a chance to act before he loses his work.
With multiple MapViews
, we will need to iterate over all active MapViews
and consult all LayerPainters
(I guess) what are their memory requirements.
follow-up: 6 comment:5 by , 9 years ago
Yes, TileCache memory usage is a big problem, especially when using JPEG images. This is is good when displaying PNG images from Opesntreetmap (size increase per tile: 200%) but not good for JPEG (requires 10 times the memory).
Since drawing takes 100 times longer we can use this to reduce the cache size by storing images we are not displaying as JPEG only.
For now, I would just stick with two separate caches (as if we had the same layer twice), replace all references to Main.map.mapView
with the local map view. We could add it to the list of next years GSoC projects ;-).
comment:6 by , 9 years ago
Replying to michael2402:
Yes, TileCache memory usage is a big problem, especially when using JPEG images. This is is good when displaying PNG images from Opesntreetmap (size increase per tile: 200%) but not good for JPEG (requires 10 times the memory).
Since drawing takes 100 times longer we can use this to reduce the cache size by storing images we are not displaying as JPEG only.
I was thinking that maybe we could "flatten" the images in the TileCache and instead keeping all the source images, and join them when painting, keep only one BufferedImage that contains all visibile Imagery Layers. This could play well with hierarchical layers (one Tile Cache per "parent" node, probably - only one node containing all imageries as children)
comment:7 by , 9 years ago
One more question. Do we want to allow different projections to be used in different Layer instances?
comment:8 by , 9 years ago
Currently: No.
But it would be a nice feature ;-). I try to use the local getProjection()
methods. You can access the current projection the map view is using with mapView.getState.getProjection()
. It would not be easy to implement at the moment since east/north coordinates are cached for the nodes so you need to have different layers in the two views. I don't see a normal use case here. If you really need this, you can just start JOSM twice ;-).
comment:10 by , 8 years ago
Milestone: | 16.09 → 16.10 |
---|
comment:13 by , 8 years ago
Milestone: | 16.12 |
---|
What is the goal:
MapView
s that share the same layersMapView
s that have different layer sets shownMapView
s that show different part of the mapFrom what I understand, what you wrote, you want to have as much flexibility as possible, but on the other hand - use the same Layer instances in all
MapView
s. As this is really good for all editable layers, in case of background imagery tiles it introduces a lot more problems than only making TileSet local to MapView.tileCache
/MemoryTileCache
inAbstractTileSourceLayer
is crucial for performance of imagery paint. On the other hand, it's one of the biggest memory consumers in JOSMLayer
instance in different zoom levels, then they will be competing for the cache entries raising the risk of cache misses and hindering performance (though the risk is not that big, as we reserve some place for tiles from lower zoom levels - for tile substitution during load)Layer
instance showing different part of the map - then frequent cache misses will be inevitable, thus I would not recommend this approach.We can use two-layered approach to memory cache, and do the LRU in one Map, that refers to other Map, that's common to all caches to reduce memory footprint. Though this not free us to have one
Layer
, that shows different part of itself in different MapViews.Maybe this (i.e. tileCache + TileSet, and all things dependant on current view of the map) is something, that needs extraction to different class.