Modify

Opened 2 years ago

Last modified 22 months 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 michael2402)

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)

mapview-window.png (1.9 MB) - added by michael2402 2 years ago.

Download all attachments as: .zip

Change History (14)

Changed 2 years ago by michael2402

Attachment: mapview-window.png added

comment:1 Changed 2 years ago by michael2402

Description: modified (diff)

comment:2 Changed 2 years ago by wiktorn

What is the goal:

  • to have a multiple MapViews that share the same layers
  • or, to have multiple MapViews that have different layer sets shown
  • or to have multiple MapViews that show different part of the map

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 MapViews. 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.

  1. tileCache / MemoryTileCache in AbstractTileSourceLayer is crucial for performance of imagery paint. On the other hand, it's one of the biggest memory consumers in JOSM
  2. 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
  3. 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)
  4. 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.
  5. 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.

comment:3 in reply to:  2 ; Changed 2 years ago by michael2402

Replying to wiktorn:

What is the goal:

  • to have a multiple MapViews that share the same layers
  • or, to have multiple MapViews that have different layer sets shown
  • or to have multiple MapViews 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 MapViews. 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.

  1. tileCache / MemoryTileCache in AbstractTileSourceLayer is crucial for performance of imagery paint. On the other hand, it's one of the biggest memory consumers in JOSM
  2. 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
  3. 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)
  4. 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.
  5. 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 in reply to:  3 Changed 2 years ago by wiktorn

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 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.

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 MapViews. 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.

comment:5 Changed 2 years ago by 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.

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 in reply to:  5 Changed 2 years ago by wiktorn

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 Changed 2 years ago by wiktorn

One more question. Do we want to allow different projections to be used in different Layer instances?

comment:8 Changed 2 years ago by michael2402

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:9 Changed 2 years ago by Don-vip

Milestone: 16.0816.09

See #13386

comment:10 Changed 2 years ago by Don-vip

Milestone: 16.0916.10

comment:11 Changed 2 years ago by simon04

Milestone: 16.1016.11

Milestone renamed

comment:12 Changed 23 months ago by Don-vip

Milestone: 16.1116.12

Milestone renamed

comment:13 Changed 22 months ago by Don-vip

Milestone: 16.12

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The owner will remain team.
as The resolution will be set.
to The owner will be changed from team to the specified user.
The owner will change to michael2402
as duplicate The resolution will be set to duplicate.The specified ticket will be cross-referenced with this ticket
The owner will be changed from team to anonymous.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.