source: josm/trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java@ 13724

Last change on this file since 13724 was 13674, checked in by Don-vip, 6 years ago

fix #16219 - smarter selection of WMS projection

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.ActionEvent;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.List;
11import java.util.Objects;
12
13import javax.swing.AbstractAction;
14import javax.swing.Action;
15
16import org.apache.commons.jcs.access.CacheAccess;
17import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
18import org.openstreetmap.josm.Main;
19import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
20import org.openstreetmap.josm.data.coor.LatLon;
21import org.openstreetmap.josm.data.imagery.AbstractWMSTileSource;
22import org.openstreetmap.josm.data.imagery.ImageryInfo;
23import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
24import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
25import org.openstreetmap.josm.data.imagery.TemplatedWMSTileSource;
26import org.openstreetmap.josm.data.imagery.WMSCachedTileLoader;
27import org.openstreetmap.josm.data.preferences.BooleanProperty;
28import org.openstreetmap.josm.data.preferences.IntegerProperty;
29import org.openstreetmap.josm.data.projection.Projection;
30import org.openstreetmap.josm.data.projection.Projections;
31import org.openstreetmap.josm.gui.MainApplication;
32import org.openstreetmap.josm.gui.layer.imagery.TileSourceDisplaySettings;
33import org.openstreetmap.josm.tools.CheckParameterUtil;
34import org.openstreetmap.josm.tools.Logging;
35import org.openstreetmap.josm.tools.Utils;
36
37/**
38 * This is a layer that grabs the current screen from an WMS server. The data
39 * fetched this way is tiled and managed to the disc to reduce server load.
40 *
41 */
42public class WMSLayer extends AbstractCachedTileSourceLayer<AbstractWMSTileSource> {
43 private static final String PREFERENCE_PREFIX = "imagery.wms";
44 /**
45 * Registers all setting properties
46 */
47 static {
48 new TileSourceDisplaySettings(PREFERENCE_PREFIX);
49 }
50
51 /** default tile size for WMS Layer */
52 public static final IntegerProperty PROP_IMAGE_SIZE = new IntegerProperty(PREFERENCE_PREFIX + ".imageSize", 512);
53
54 /** should WMS layer autozoom in default mode */
55 public static final BooleanProperty PROP_DEFAULT_AUTOZOOM = new BooleanProperty(PREFERENCE_PREFIX + ".default_autozoom", true);
56
57 private static final String CACHE_REGION_NAME = "WMS";
58
59 private final List<String> serverProjections;
60
61 /**
62 * Constructs a new {@code WMSLayer}.
63 * @param info ImageryInfo description of the layer
64 */
65 public WMSLayer(ImageryInfo info) {
66 super(info);
67 CheckParameterUtil.ensureThat(info.getImageryType() == ImageryType.WMS, "ImageryType is WMS");
68 CheckParameterUtil.ensureParameterNotNull(info.getUrl(), "info.url");
69 TemplatedWMSTileSource.checkUrl(info.getUrl());
70 this.serverProjections = new ArrayList<>(info.getServerProjections());
71 }
72
73 @Override
74 protected TileSourceDisplaySettings createDisplaySettings() {
75 return new TileSourceDisplaySettings(PREFERENCE_PREFIX);
76 }
77
78 @Override
79 public Action[] getMenuEntries() {
80 List<Action> ret = new ArrayList<>();
81 ret.addAll(Arrays.asList(super.getMenuEntries()));
82 ret.add(SeparatorLayerAction.INSTANCE);
83 ret.add(new LayerSaveAction(this));
84 ret.add(new LayerSaveAsAction(this));
85 ret.add(new BookmarkWmsAction());
86 return ret.toArray(new Action[0]);
87 }
88
89 @Override
90 protected AbstractWMSTileSource getTileSource() {
91 AbstractWMSTileSource tileSource = new TemplatedWMSTileSource(
92 info, chooseProjection(Main.getProjection()));
93 info.setAttribution(tileSource);
94 return tileSource;
95 }
96
97 /**
98 * This action will add a WMS layer menu entry with the current WMS layer
99 * URL and name extended by the current resolution.
100 * When using the menu entry again, the WMS cache will be used properly.
101 */
102 public class BookmarkWmsAction extends AbstractAction {
103 /**
104 * Constructs a new {@code BookmarkWmsAction}.
105 */
106 public BookmarkWmsAction() {
107 super(tr("Set WMS Bookmark"));
108 }
109
110 @Override
111 public void actionPerformed(ActionEvent ev) {
112 ImageryLayerInfo.addLayer(new ImageryInfo(info));
113 }
114 }
115
116 @Override
117 public Collection<String> getNativeProjections() {
118 return serverProjections;
119 }
120
121 @Override
122 public void projectionChanged(Projection oldValue, Projection newValue) {
123 super.projectionChanged(oldValue, newValue);
124 Projection tileProjection = chooseProjection(newValue);
125 if (!Objects.equals(tileSource.getTileProjection(), tileProjection)) {
126 tileSource.setTileProjection(tileProjection);
127 }
128 }
129
130 private Projection chooseProjection(Projection requested) {
131 if (serverProjections.contains(requested.toCode())) {
132 return requested;
133 } else {
134 LatLon center = MainApplication.isDisplayingMapView() ?
135 requested.eastNorth2latlon(MainApplication.getMap().mapView.getCenter()) : null;
136 Projection firstNonNullproj = null;
137 Projection firstProjInBounds = null;
138 for (String code : serverProjections) {
139 Projection proj = Projections.getProjectionByCode(code);
140 if (proj != null) {
141 if (firstNonNullproj == null) {
142 firstNonNullproj = proj;
143 }
144 if (center != null && proj.getWorldBoundsLatLon().contains(center)) {
145 firstProjInBounds = proj;
146 break;
147 }
148 }
149 }
150 if (firstProjInBounds != null) {
151 return selectProjection(firstProjInBounds);
152 } else if (firstNonNullproj != null) {
153 return selectProjection(firstNonNullproj);
154 }
155 Logging.warn(tr("Unable to find supported projection for layer {0}. Using {1}.", getName(), requested.toCode()));
156 return requested;
157 }
158 }
159
160 private Projection selectProjection(Projection proj) {
161 Logging.info(tr("Reprojecting layer {0} from {1} to {2}. For best image quality and performance,"
162 + " switch to one of the supported projections: {3}",
163 getName(), proj.toCode(), Main.getProjection().toCode(), Utils.join(", ", getNativeProjections())));
164 return proj;
165 }
166
167 @Override
168 protected Class<? extends TileLoader> getTileLoaderClass() {
169 return WMSCachedTileLoader.class;
170 }
171
172 @Override
173 protected String getCacheName() {
174 return CACHE_REGION_NAME;
175 }
176
177 /**
178 * @return cache region for WMS layer
179 */
180 public static CacheAccess<String, BufferedImageCacheEntry> getCache() {
181 return AbstractCachedTileSourceLayer.getCache(CACHE_REGION_NAME);
182 }
183}
Note: See TracBrowser for help on using the repository browser.